/*
Copyright (c) 2002, Matthias Bauer, LIVINGLOGIC AG, BAYREUTH
All rights reserved.

Redistribution and use in source and binary forms, with or without 
modification, are permitted provided that the following conditions are 
met:

    1. Redistributions of source code must retain the above copyright 
       notice, this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright 
       notice, this list of conditions and the following disclaimer in the 
       documentation and/or other materials provided with the distribution.
    3. The end-user documentation included with the redistribution, if
       any, must include the following acknowlegement:
       "This product includes software developed by 
        Matthias Bauer, LIVINGLOGIC AG, BAYREUTH 
        (http://www.livinglogic.de/)."
       Alternately, this acknowlegement may appear in the software itself,
       if and wherever such third-party acknowlegements normally appear.
    4. Neither the name of Matthias Bauer, nor the LIVINGLOGIC AG nor the 
       names of the other contributors may be used to endorse or promote 
       products derived from this software without specific prior written
       permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
POSSIBILITY OF SUCH DAMAGE.
*/

package es.ejie.frmk.presentacion.operacion;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;

import javax.servlet.ServletException;
import javax.servlet.UnavailableException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionBindingEvent;

import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.lang.StringUtils;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.DynaActionFormClass;
import org.apache.struts.config.FormBeanConfig;
import org.apache.struts.util.RequestUtils;

import es.ejie.frmk.control.apilamiento.Q70GestorDeApilamiento;
import es.ejie.frmk.control.arranque.Q70GestorArranqueConfiguracion;
import es.ejie.frmk.control.excepciones.Q70FrameworkException;
import es.ejie.frmk.infraestructura.logs.incidencias.Q70LogIncidencias;
import es.ejie.frmk.infraestructura.seguridad.Q70AuthorizationException;
import es.ejie.frmk.infraestructura.seguridad.Q70GestorSeguridad;
import es.ejie.frmk.infraestructura.seguridad.Q70InformacionSeguridadUsuario;
import es.ejie.frmk.infraestructura.seguridad.Q70LogonException;
import es.ejie.frmk.infraestructura.seguridad.Q70SeguridadException;
import es.ejie.frmk.infraestructura.traza.Q70TraceLevel;
import es.ejie.frmk.infraestructura.traza.Q70Traza;
import es.ejie.frmk.infraestructura.utilidades.constantes.Q70UtilidadesConstantes;
import es.ejie.frmk.infraestructura.utilidades.mapeador.Q70GestorMapeador;
import es.ejie.frmk.listeners.base.Q70LogDataUtils;
import es.ejie.frmk.presentacion.anomala.Q70GestorDeNavegacionAnomala;
import es.ejie.frmk.presentacion.base.Q70Constantes;
import es.ejie.frmk.presentacion.base.Q70PasosOPMapping;
import es.ejie.frmk.presentacion.base.Q70Workflow;
import es.ejie.frmk.presentacion.base.Q70WorkflowContainer;
import es.ejie.frmk.presentacion.operacion.datos.Q70ContextoOperacionDePresentacion;
import es.ejie.frmk.presentacion.operacion.datos.Q70OPForm;
import es.ejie.frmk.presentacion.operacion.datos.Q70OPValidatorForm;
import es.ejie.frmk.presentacion.operacion.paso.Q70ActionPasoOP;
import es.ejie.frmk.presentacion.sesiondatos.Q70ContextoEJIE;
import es.ejie.frmk.presentacion.sesiondatos.Q70ContextoJerarquicoEJIE;
import es.ejie.frmk.presentacion.sesiondatos.Q70ContextosEnMemoriaManejador;
import es.ejie.frmk.presentacion.sesiondatos.Q70HttpSesionEscuchador;
import es.ejie.frmk.presentacion.sesiondatos.Q70SesionDatos;



/**
 * @author sp86601
 */
/**
 * Esta clase contiene la lógica de presentación de una operación de acceso.
 * <p>
 * El núcleo de la funcionalidad del componente de <b>Operación de Presentación</b> 
 * se concentra en su método <b>process()</b> que marca el flujo de la secuencia de
 * llamadas a métodos que permiten a la Operación de Presentación colaborar con otros 
 * componentes de Geremua (validaciones, seguridad, navegación anómala).
 * Al centralizar el procesamiento de la petición, la funcionalidad es única provenga 
 * la petición de un Procesador de Tiles o no. 
 * <p>
 * @author M. Bauer
 * */

public class Q70LogicaOperacionDePresentacion
{
	/**
	 * Constante que indica el componente al que pertenece la clase. Es
	 * necesario para el uso del log de trazas.
	 */
	private static final String COMPONENTE = "OPERACION_PRESENTACION";
	
	/**
	 * Instancia del log de trazas
	 */
	private static Q70Traza tr = Q70Traza.getSingleton();
	
	/**
	 * Instancia de procesador que recoge la petición y delega su procesamiento.
	 */
	private Q70AdaptadorLogicaOperacionDePresentacion rp;	
	
	/**
	 * Clave usada para almacenar en un atributo de la request
	 * el identificador del paso de Operación de Presentación 
	 * que causó una violación del flujo de navegación.
	 */
	public final static String NEXT_STATE_VIOLATION_PATH = "es.ejie.frmk.presentacion.operacion.LogicaOperacionPresentacion.nextStateViolationPath";
		
	/**
	 * Nombre de la operación de presentación por defecto. 
	 */
	public final static String DEFAULT_OP = "_DEFAULT";

	
	/**
	 * Estructura de instancias de clases que implementan <b>Authentication</b>.
	 * La clave es el nombre de clase complementamente calificada.
	 */
	protected Hashtable authClasses = new Hashtable();

	/**
	 * Prefijo usado para encontrar la instancia de ActionForward indicada para responder a
	 * una violación de flujo de navegación determinada. 
	 */
	public static String WORKFLOW_VIOLATION_FORWARD_PREFIX = "violacionFlujo_";
	
	/**
	 * Constructor
	 * @param rp Instancia de procesador que recoge la petición y delega su procesamiento.
	 */
	Q70LogicaOperacionDePresentacion(Q70AdaptadorLogicaOperacionDePresentacion rp)
	{
		this.rp = rp;
	}

	/**
	 * Método que registra información acerca del estado actual de la navegación
	 * @param <code>workflowContainer</code> Diálogo asociado al usuario
	 */
	protected void logStates(Q70WorkflowContainer workflowContainer)
	{
		if (tr.isTraceActive())
		{
			Set workflowLabels = workflowContainer.getWorkflowLabels();
			if (0==workflowLabels.size())
			{
				tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "No se han definido workflows.");
			}
			else
			{
				StringBuffer debugText = new StringBuffer(500);
				
				tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Workflows Definidos: ");
	
				/* Iterate through all active workflows */
				Iterator it = workflowLabels.iterator();
				while (it.hasNext())
				{
					debugText.setLength(0);
					debugText.append("  ");
					
					String workflowLabel = (String)it.next();
					debugText.append(workflowLabel).append(" -");
	
					Q70Workflow workflow = workflowContainer.get(workflowLabel);
					debugText.append(" Estado Actual: ").append(workflow.getCurrentState());
	
					Set definedNextStates = workflow.getDefinedNextStates();
					if (null != definedNextStates)
					{
						debugText.append(", Estados 'next' definidos: ").append(definedNextStates);
					}
	
					Set attributeNames = workflow.getAttributeNames();
					if (null != attributeNames)
					{
						debugText.append(", Nombres de atributos: ").append( attributeNames);
					}
					Set cleanupActionNames = workflow.getCleanupObjectNames();
					if (null != cleanupActionNames)
					{
						debugText.append(", Nombre del Cleanup action: ").append(cleanupActionNames);
					}
					tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, debugText.toString());
				}
			}
		}
	}

	

	/**
	 * Modifica el estado del Diálogo del usuario
	 * @param <code>request</code> Petición a procesar
	 * @param <code>workflowMapping</code> Juego de pasos de Operación de Presentación donde buscar el paso actual
	 * @param <code>workflowContainer</code> Diálogo asociado al usuario
	 */
	protected void updateWorkflows(HttpServletRequest request, Q70PasosOPMapping workflowMapping, Q70WorkflowContainer workflowContainer)
	{
		Collection workflowLabels = workflowMapping.getWorkflows();

		if (0 < workflowLabels.size())
		{
			workflowContainer.setPrimaryLabel(workflowMapping.getPrimary());
			
			Iterator it = workflowLabels.iterator();
			while (it.hasNext())
			{
				String workflowLabel = (String)it.next();
				Q70PasosOPMapping.WorkflowData workflowData = workflowMapping.getWorkflowData(workflowLabel);
				boolean endsWorkflow = workflowData.getEndsWorkflow();
				String newState = workflowData.getNewState();
				Set definedNextStates = workflowData.getNextStates();
				
				if (tr.isTraceActive())
				{
					if (endsWorkflow || (newState != null) || (!definedNextStates.isEmpty()))
					{
						tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Actualizando workflow: " + workflowLabel);

						if (endsWorkflow)
						{
							tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "  Eliminando este workflow de la session");
						}
						else
						{
							if (newState != null)
							{
								tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "  Poniendo el estado actual a " + newState);
							}
							if (!definedNextStates.isEmpty())
							{
								tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "  Poniendo los estados 'next' a " + definedNextStates);
							}
						}
					}
				}
				
				if (endsWorkflow)
				{
					workflowContainer.remove(request, workflowLabel);
				}
				else
				{
					Q70Workflow workflow = workflowContainer.getOrCreate(workflowLabel);
					if (newState != null)
					{
						workflow.setCurrentState(newState);
					}
					workflow.setDefinedNextStates(definedNextStates);
				}
			}
		}
	}

	/**
	 * 
	 * <p>Procesa una <code>HttpServletRequest</code> y crea la
	 * correspondiente <code>HttpServletResponse</code>.</p>
	 * @param <code>request</code> Petición a procesar
	 * @param <code>response</code> Respuesta a crear
	 * @exception <code>IOException</code> si sucede un error de entrada/salida
	 * @exception <code>ServletException</code> si sucede una excepción de procesamiento
	 */
	public void process(HttpServletRequest request,
						HttpServletResponse response)
		throws Q70FrameworkException {
		try {

			// Wrap multipart requests with a special wrapper
			request = rp.processMultipart(request);
	
			// Identify the path component we will use to select a mapping
			String path = rp.processPath(request, response);
			if (path == null) {
				return;
			}
			
			// Select a Locale for the current user if requested
			rp.processLocale(request, response);
	
			// Set the content type and no-caching headers if requested
			rp.processContent(request, response);
			rp.processNoCache(request, response);
	
			// General purpose preprocessing hook
			if (!rp.processPreprocess(request, response)) {
				return;
			}
	
			// Identify the mapping for this request
			ActionMapping mapping = rp.processMapping(request, response, path);
			if (mapping == null) {
				return;
			}
	
			//Preparamos los datos necesarios para el componente de logs.
			Q70LogDataUtils.finalPrepareLogData(request, COMPONENTE);
	
			// start workflow checks
			Q70PasosOPMapping workflowMapping;
			try
			{
				workflowMapping = (Q70PasosOPMapping) mapping;
			}
			catch (ClassCastException cce)
			{
				throw new UnavailableException(
					"Este action mapping no es una subclase de Q70PasosOPMapping.\nFalta esta línea en el struts-config correspondiente:\n<action-mappings type='es.ejie.frmk.presentacion.base.Q70PasosOPMapping'>"
				);  	
			}
			
			HttpSession session = request.getSession();
			Q70WorkflowContainer workflowContainer = Q70WorkflowContainer.get(session);

			//Guardamos el response de la última petición que nos haya llegado, para poder 
			//controlar el doble-click (Volver a pedir un recurso de OP si aún no ha terminado
			//su anterior ejecución para ese usuario)
			Q70GestorDeNavegacionAnomala.getInstance().processDobleClick (workflowMapping, request, response);
			
			//we synchronize on the workflow container of the user, so he cannot
			// fool our workflow checks by starting two actions in quick succession
			synchronized(workflowContainer)
			{
				if (response.isCommitted())
					return;
				
				logStates(workflowContainer);
				//Procesamiento de detección de ruptura de flujo de navegación (Navegación Anómala)
				if (!Q70GestorDeNavegacionAnomala.getInstance().processRupturaFlujo(rp,workflowMapping, workflowContainer, request, response))
				{
					return;
				}

				// Check for any role required to perform this action
				if (!rp.processRoles(request, response, mapping)) {
					return;
				}
				
				// Gestión del contexto de la Operación de Presentación
				if (!processContext(request, response, mapping, workflowMapping))
				{
					return;
				}
				
				// update the workflow data 
				updateWorkflows(request, workflowMapping, workflowContainer);
				
				// Process any ActionForm bean related to this request
				ActionForm form = rp.processActionForm(request, response, mapping);
				rp.processPopulate(request, response, form, mapping);
								
				if (!rp.processValidate(request, response, form, mapping))
				{
					if (tr.isTraceActive())
					{
						tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "El formulario " + form.getClass() + " no satisface las validaciones asignadas. Dejando la siguiente marca en la request: ["+Q70Constantes.FORM_VALIDATION_ERROR_KEY+"=true] ...");
					}
					
					//Poner en la request la marca indicando que no se han satisfecho las validaciones de formulario
					request.setAttribute(Q70Constantes.FORM_VALIDATION_ERROR_KEY, new Boolean("true"));
					// Se pide al singleton Gestor de Navegación Anómala que borre la marca de control de 
					// doble-click para los actions que no han pasado la validación.
					Q70GestorDeNavegacionAnomala.getInstance().cleanDobleClick(request);
					
					return;
				}
	
				
				//	Mapeo de datos de formulario de entrada a estructura de contexto
				if (null != form)
				{
					if (tr.isTraceActive())
					{
						if (form instanceof Q70OPValidatorForm)
						{
							tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Formulario de operación de presentación (con validator):\n"+((Q70OPValidatorForm)form).toString());
						}
						else if (form instanceof Q70OPForm)
						{
							tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Formulario de operación de presentación:\n"+((Q70OPForm)form).toString());
						}
					}
					if (!mappingFormToContext (session,form)) {
						return;
					}
				}
				
				// Si existe la propiedad "mapa" en Q70PasosOpMapping
				// realizamos el mapeo correspondiente
				processMapeoContexto((Q70PasosOPMapping)mapping, session);
				
				// Si existe la propiedad "erase" en Q70PasosOpMapping
				// realizamos la inicialización de los atributos del contexto
				// correspondientes.
				processInicializacionContexto((Q70PasosOPMapping)mapping, session);
			
				// Retorna a la superoperación (op. invocante) si estamos al final
				// de una suboperación. 
				if (!Q70GestorDeApilamiento.getSingleton().processApilamiento(request, response, workflowMapping, null, rp.getServlet())) {
					return;
				}
				
				// Process a forward or include specified by this mapping
				if (null != mapping.getForward())
				{
					if (tr.isTraceActive())
					{
						tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Entra por atributo <forward> = "+mapping.getForward());
					}
				}
				if (!rp.processForward(request, response, mapping)) {
					if (tr.isTraceActive())
					{
						tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Sale por atributo <forward> = "+mapping.getForward());
					}
					return;
				}
				if (null != mapping.getInclude())
				{
					if (tr.isTraceActive())
					{
						tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Entra por atributo <include> = "+mapping.getInclude());
					}
				}
				if (!rp.processInclude(request, response, mapping)) {
					if (tr.isTraceActive())
					{
						tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Sale por atributo <include> = "+mapping.getInclude());
					}
					return;
				}
	
				// Create or acquire the Action instance to process this request
				Action action = rp.processActionCreate(request, response, mapping);
				if (action == null) {
					return;
				}
				
				if (tr.isTraceActive())
				{
					tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Procesando Action (Paso de OP): "+action.getClass().toString());
				}
				
				if (!(action instanceof Q70ActionPasoOP))
				{
					//Se pide al singleton Gestor de Navegación Anómala que borre la marca de control de 
					//doble-click para los actions que no son implementados por la aplicación.
					Q70GestorDeNavegacionAnomala.getInstance().cleanDobleClick(request);
				}
				
				//Call the Action instance itself
				ActionForward forward = rp.processActionPerform(request, response, action, form, mapping);
				//Se pide al singleton Gestor de Navegación Anómala que devuelva el response almacenado
				HttpServletResponse responseEnVigor = Q70GestorDeNavegacionAnomala.getInstance().getDobleClickResponse(request);
				
				if (null != responseEnVigor)
				{
					if(!response.equals(responseEnVigor))
					{
						if (tr.isTraceActive())
						{
							tr.trace(COMPONENTE, Q70TraceLevel.INFO, "Cambiando response de la primera petición por el de la última (tratamiento del doble click).");
						}
					}
					//Recurso de Operacion de Presentacion finalizado
					Q70GestorDeNavegacionAnomala.getInstance().cleanDobleClick(request);
					//Process the returned ActionForward instance
					rp.processForwardConfig(request, responseEnVigor, forward);
				}
				else
				{
					// Process the returned ActionForward instance
					rp.processForwardConfig(request, response, forward);
				}
			}
		}
		catch (ServletException se) {
			//Recurso de Operacion de Presentacion no finalizado correctamente
			//borramos el registro del doble-click
			Q70GestorDeNavegacionAnomala.getInstance().cleanDobleClick(request);
			//Buscamos una FrameworkException dentro de la ServletException
			//originada por un tag de Geremua. 
			Throwable aux = (Throwable)se.getRootCause();
			boolean encontrado = false;
			while (null != aux && !encontrado)
			{
				if (aux instanceof Q70FrameworkException)
				{
					encontrado = true;
				}
				else if (aux instanceof ServletException)
				{
					aux = ((ServletException)aux).getRootCause();
				}
				else aux = null;
			}
			if (encontrado)
			{
				throw new Q70OperacionDePresentacionException(this.getClass().toString(),"process","Excepcion recogida.",aux);
			}
			else
			{
				throw new Q70OperacionDePresentacionException(this.getClass().toString(),"process","Excepcion recogida.",se);
			}			 
		}
		catch (Exception e) {
			//Recurso de Operacion de Presentacion no finalizado correctamente
			//borramos el registro del doble-click
			Q70GestorDeNavegacionAnomala.getInstance().cleanDobleClick(request);
			throw new Q70OperacionDePresentacionException(this.getClass().toString(),"process","Excepcion recogida.",e);
		}
	}

//*********************************************************************************************************	

	/**
	 * Procesamiento de Contextos. 
	 * <p>
	 * Gestiona la creación y cambio de contextos de 
	 * operación, de usuario y globales.
	 * 
	 * @param <code>HttpServletRequest</code>
	 * @param <code>HttpServletResponse</code>
	 * @param <code>ActionMapping</code>
	 * @param <code>Q70PasosOPMapping</code>
	 * @return <code>true</code> Si no hay problemas
	 * @throws <code>FrameworkException</code>
	 */
	protected boolean processContext (HttpServletRequest req, HttpServletResponse res, ActionMapping mapping, Q70PasosOPMapping workflowMapping) throws Q70FrameworkException
	{
		//Inicializaciones
		String textoMensaje = null;
		String aplicacion = null;
		String viejaOp = null;
		String nuevaOp = null;
		Q70SesionDatos sesionDatos = null; 
		Q70ContextoEJIE contexto = null;
		HttpSession session = null;
		boolean mismoContexto = false;
		try
		{
			textoMensaje = "Recuperando contexto";
			sesionDatos = Q70SesionDatos.getSingleton();
			session = req.getSession();
			//Recuperación de contexto
			contexto = (Q70ContextoEJIE)session.getAttribute(Q70Constantes.CONTEXT);
			//Calculo de nombre de aplicación
			aplicacion = (String)req.getSession().getServletContext().getInitParameter(Q70GestorArranqueConfiguracion.NOMBRE_APLICACION);
			if (tr.isTraceActive())
			{
				tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Aplicación = "+aplicacion);
			}
			//Calculo de nombre de nueva OP
			nuevaOp = mapping.getModuleConfig().getPrefix();
			if (0 == nuevaOp.length())
			{
				nuevaOp = DEFAULT_OP;
			}
			
			//Crear o Recuperar el contexto de OP y la lista de contextos, 
			// incluído el de Sesion usuario (y la informacion de seguridad del usuario)
			if (null == contexto)
			{
				if (tr.isTraceActive())
				{
					tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Nueva Operación: |-> "+nuevaOp+" (nuevo contexto)");
				}
				textoMensaje = "inicializar contextos";
				contexto = processInicializacionContextos(aplicacion, nuevaOp, null, mapping, req, res);
			}
			else
			{
				//Ya existe contexto, averiguamos antigua OP
				viejaOp = contexto.getIdContexto();
				if (tr.isTraceActive())
				{
					tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Operación de Presentación: "+viejaOp+" -> "+nuevaOp);
				}
				if (viejaOp.equals(nuevaOp))
				{
					if (tr.isTraceActive())
					{
						tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Estamos dentro de la misma operación (mismo contexto)");
					}

					//Comprobar el tipo de usuario guardado en la sesion
					if (Q70SesionDatos.getSingleton().getContexto(contexto,Q70SesionDatos.CTX_SESION_USUARIO).getIdContexto().indexOf(Q70Constantes.DEFAULT_USER)==0){
						//Se trataba de un usuario ANONIMO
						
						//Se intenta crear la informacion de seguridad usuario, 
						// si es posible entonces es que el nuevo usuario NO se trata de un usuario ANONIMO.
						Q70InformacionSeguridadUsuario informacionSeguridadUsuario = null;
						try {
							informacionSeguridadUsuario = crearInformacionSeguridadUsuario(req);
						} catch (Q70LogonException e) {
							//Si da esta excepcion es que no existe un usuario LOGEADO, 
							// y por tanto, se trata de un usuario ANONIMO.
						}
						if (null != informacionSeguridadUsuario){
							//El nuevo usuario esta LOGEADO, entonces hay que cambiar los contextos
							// de sesion usuario, por estos y dejar igual el contexto de operacion
							
							//Reconstruir los contextos sesion usuario, grupo aplicacion y departmento
							if (tr.isTraceActive())
							{
								tr.trace(COMPONENTE, Q70TraceLevel.INFO, "Reconstruimos los contextos sesion usuario, grupo aplicacion y departmento.");
							}
							textoMensaje = "reconstruir contextos sesion usuario, grupo aplicacion y departmento";
							
							//Invalida al usuario anonimo del servidor
							Q70HttpSesionEscuchador escuchador = (Q70HttpSesionEscuchador) req.getSession().getAttribute(Q70Constantes.CONTEXT_SESSION_LISTENER);
							if (escuchador != null) {
								if (contexto != null) {
									escuchador.valueUnbound(new HttpSessionBindingEvent(req.getSession(), Q70Constantes.CONTEXT_SESSION_LISTENER) {
										private static final long serialVersionUID = 1L;
									});
									setContextoEnHttpSession(session, null);
								}
							}
							
							//Crea el contexto con el usuario correcto
							contexto = processInicializacionContextos(aplicacion, nuevaOp, contexto, mapping, req, res);
						}else{
							//El nuevo usuario es ANONIMO, suponemos que es el mismo						
							mismoContexto = true;
						}
					}else{
						//Se trataba de un usuario LOGEADO, suponemos que es el mismo						
						mismoContexto = true;
					}
				}
				else
				{
					//Es una nueva Operación de Presentación. (OP)
					if (tr.isTraceActive())
					{
						tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Cambio de operación (cambio de contexto)");
					}
					//Si la nueva OP tiene función de autorización y además el usuario que creó los contextos
					//globales actuales fue anónimo, hay que reconstruir los contextos globales
					if(!esValidoContextoAnonimo(req, contexto, nuevaOp))
					{
						//Reconstruir los contextos globales
						if (tr.isTraceActive())
						{
							tr.trace(COMPONENTE, Q70TraceLevel.INFO, "Reconstruimos los contextos globales.");
						}
						textoMensaje = "reconstruir contextos";
						
						//Invalida al usuario anonimo del servidor
						Q70HttpSesionEscuchador escuchador = (Q70HttpSesionEscuchador) req.getSession().getAttribute(Q70Constantes.CONTEXT_SESSION_LISTENER);
						if (escuchador != null) {
							if (contexto != null) {
								escuchador.valueUnbound(new HttpSessionBindingEvent(req.getSession(), Q70Constantes.CONTEXT_SESSION_LISTENER) {
									private static final long serialVersionUID = 1L;
								});
								setContextoEnHttpSession(session, null);
							}
						}
						
						//Crea el contexto con el usuario correcto
						contexto = processInicializacionContextos(aplicacion, nuevaOp, null, mapping, req, res);
					}
					else
					{
						textoMensaje = "añadir contexto";
						//Salva lista anterior de antecesores
						List aux = sesionDatos.getListaContextos(contexto);
						//Creación de nuevo contexto pasandole la definición de contextoOP del struts-config 
						contexto = sesionDatos.crearContextoOperacion(getEstructuraDeContexto(mapping), nuevaOp);
						//Añade al contexto los contextos jerárquicos superiores
						contexto = sesionDatos.addListaContextos(contexto, aux);
					}
				}
			}
			
			//Comprobar si tiene el usuario tiene Función de Autorización para ejecutar la Operación de Presentación
			textoMensaje = "procesar autorización";
			// Esto es necesario:
			// - Si NO hay contexto, para procesar la funcion de autorización.
			// - Si hay cambio de OP, para procesar una posible nueva funcion de autorización.
			// - Si NO hay cambio de OP, puede ser necesario reconstruir el contexto de seguridad,
			//   ya que puede estar a null, o mal construida. Como por ejemplo, cuando se replica el contexto
			//   de sesion usuario en servidores trabajando en cluster.
			processFuncionAutorizacion(req, aplicacion, nuevaOp, contexto);
			//Llamada a la gestion de Seguridad a nivel de funcionalidad, es decir, se comprueba, en caso de que 
			//se haya indicado con el atributo secureId, que el usuario tenga permisos en la funcionalidad pulsada.
			processSecureId(req,workflowMapping,contexto,aplicacion,nuevaOp);
			
			if (!mismoContexto)
			{
				//Si no había contexto o la OP es distinta a la anterior, actualizar contexto
				setContextoEnHttpSession(session, contexto);
				
				// Jgrey : Para invalidar la sesion **************************************
				Q70HttpSesionEscuchador escuchador = (Q70HttpSesionEscuchador)req.getSession().getAttribute(Q70Constantes.CONTEXT_SESSION_LISTENER); 
				if (  escuchador == null ){
					escuchador = new Q70HttpSesionEscuchador();
				}else{
					if ( !escuchador.isInicialized() ){
						if ( contexto != null ){
							escuchador.valueBound(new HttpSessionBindingEvent(req.getSession(),Q70Constantes.CONTEXT_SESSION_LISTENER){
								private static final long serialVersionUID = 1L;
							});
						}
					}
				}
				req.getSession().setAttribute(Q70Constantes.CONTEXT_SESSION_LISTENER,escuchador);
			}
			textoMensaje = "procesar apilamiento";
			Q70GestorDeApilamiento.getSingleton().processApilamiento(req, null, workflowMapping, contexto, null);

			return true;	
		}
		catch(Exception e)
		{
			if (tr.isTraceActive())
			{
				tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "ERROR al " + textoMensaje);
			}
			throw new Q70OperacionDePresentacionException(this.getClass().toString(),"processContext","ERROR al " + textoMensaje,e);
		}
	}
	
	/**
	 * Mapeo de datos del formulario de entrada al contexto de operación de
	 * presentación.
	 * 
	 * @param <code>HttpSession</code> Sesión de usuario
	 * @param <code>ActionForm</code> Bean de formulario de entrada.
	 * @return <code>true</code> Si todo ha ido bien.
	 * @throws <code>FrameworkException</code>
	 */
	protected boolean mappingFormToContext (HttpSession session, ActionForm form) throws Q70FrameworkException
	{
		Q70ContextoEJIE contexto;
		try {
			if (tr.isTraceActive())
			{
				tr.trace(COMPONENTE, Q70TraceLevel.INFO, "Mapeando datos del Form de Entrada al Contexto....");
			}
			//Mapeo de datos de formulario de entrada a estructura de contexto
			//Recuperación de contexto
			contexto = (Q70ContextoEJIE) session.getAttribute(Q70Constantes.CONTEXT);
			Q70GestorMapeador mapeador = Q70GestorMapeador.getSingleton();
			mapeador.mapObjects(Q70UtilidadesConstantes.MAPA_TODAS_PROPIEDADES, (DynaBean)form, contexto);
			setContextoEnHttpSession(session, contexto);
			return true;	
		} catch (Exception e) {
			if (tr.isTraceActive())
			{
				tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "ERROR mapeando datos del Form de Entrada al Contexto.");
			}
			throw new Q70OperacionDePresentacionException(this.getClass().toString(),"processContext","ERROR mapeando datos del Form de Entrada al Contexto.",e);
		}
	}

	/**
	 * Método que recupera la estructura del Contexto de Operación de Presentación.
	 * <P>
	 * La estructura del Contexto de Operación de Presentación se presenta en el fichero de configuración 
	 * de la Operación de Presentación correspondiente.
	 * 
	 * @param <code>ActionMapping</code> Información de configuración de la Operación de Presentación.
	 * @return <code>Q70ContextoOperacionDePresentacion</code>
	 * @throws <code>FrameworkException</code>
	 */
	protected Q70ContextoOperacionDePresentacion getEstructuraDeContexto (ActionMapping mapping) throws Q70FrameworkException
	{
		Q70ContextoOperacionDePresentacion estructuraContexto = null;
		try {
			FormBeanConfig cfg = mapping.getModuleConfig().findFormBeanConfig(Q70Constantes.OP_CONTEXT);
			estructuraContexto = (Q70ContextoOperacionDePresentacion)DynaActionFormClass.createDynaActionFormClass(cfg).newInstance();			
		} catch (Exception e) {
			if (tr.isTraceActive())
			{
				tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "Error al recuperar la estructura de contexto.\nPosiblemente no esté definido en el struts-config correspondiente.\n<form-bean name='contextoOP' type='es.ejie.frmk.presentacion.operacion.Q70ContextoOperacionDePresentacion'>");
			}
			throw new Q70OperacionDePresentacionException (this.getClass().toString(),"execute","Error al recuperar la estructura de contexto.",e);
		}
		return estructuraContexto;
	}
	
	/**
	 * Método que procesa las validaciones de autorización asociadas a la Operación de Presentación.
	 * <p>
	 * Recupera la Función de Autorización indicada en el fichero de configuración de la Operación de Presentación.
	 * Si existe la Función de Autorización, pide al contexto de Usuario el atributo "informacion de seguridad de
	 * usuario". 
	 * Si no existe, pide al Gestor de Seguridad que construya un atributo "informacion de seguridad de usuario"
	 * anónimo y lo deposita en el contexto de Usuario.
	 * Después pide al Gestor de Seguridad que chequee si la Función de Autorización es válida para la informacion
	 * de seguridad de usuario
	 * @param <code>HttpServletRequest</code> Petición a procesar 
	 * @param <code>aplicacion</code> Nombre de Aplicación
	 * @param <code>operacionPresentacion</code> Nombre de Operación de Presentación 
	 * @param <code>Contexto</code> Estructura de Contextos 
	 * @throws <code>FrameworkException</code>
	 */	
	protected void processFuncionAutorizacion(HttpServletRequest request, String aplicacion, String operacionPresentacion, Q70ContextoEJIE contexto) throws Q70FrameworkException
	{
		String back = null;
		String funcionAutorizacion = null;
		
		if (tr.isTraceActive())
		{
			tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Comprobando autorización para ejecutar la Operación de Presentación "+operacionPresentacion);
		}
		try
		{
			Q70DatosOPConfig datosOPConfig = (Q70DatosOPConfig)request.getSession().getServletContext().getAttribute(Q70DatosOPPlugIn.DATOSOP_KEY+operacionPresentacion);
			if (null != datosOPConfig)
			{
				funcionAutorizacion = datosOPConfig.getFuncionAutorizacion();
			}
			if (null == funcionAutorizacion)
			{
				if (tr.isTraceActive())
				{
					tr.trace(COMPONENTE, Q70TraceLevel.INFO, "La operación de presentación "+operacionPresentacion+" no tiene función de autorización (no requiere logon).");
				}
			}
			else
			{
				if (tr.isTraceActive())
				{
					tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Función de autorización para la Operación de Presentación "+operacionPresentacion+": "+funcionAutorizacion);
				}
				//Comprobamos que existe la información de seguridad de usuario y si es posible se crea.
				Q70InformacionSeguridadUsuario informacionSeguridadUsuario = processSeguridadUsuario(request, operacionPresentacion, contexto);
				//Llamamos al Gestor de Seguridad para comprobar si tiene autorización
				try
				{
					if ("".equals(funcionAutorizacion)){
						if (tr.isTraceActive())
						{
							tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "La Funcion de Autorización esta en blanco para la Operacion de Presentacion"+operacionPresentacion);
						}
						throw new Q70FrameworkException(COMPONENTE,this.getClass().toString(),"processFuncionAutorizacion","La Funcion de Autorización esta en blanco para la Operacion de Presentacion "+operacionPresentacion,null); 
					}
					Q70GestorSeguridad.getSingleton().checkAuthorization(informacionSeguridadUsuario,aplicacion, funcionAutorizacion);
				}
				catch (Q70LogonException e)
				{
					back = RequestUtils.requestURL(request).toString();
					if (tr.isTraceActive())
					{
						tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "El usuario ha sido desconectado durante la Operación de Presentación "+operacionPresentacion);
						tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "URL de regreso tras reenvío a Página de Logon = "+back);
					}
					Q70LogonException le = new Q70LogonException(((Q70LogonException)e).getClase(),((Q70LogonException)e).getMetodo(),((Q70LogonException)e).getMessage(),((Q70LogonException)e).getThrowable());
					le.setRetPath(back);
					if (tr.isTraceActive())
					{
						tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "[Q70LogonException]= Componente : "+le.getComponente()+ " Clase : "+le.getClase()+ " Metodo : "+le.getMetodo()+ " Q70Mensaje : "+le.getMessage()+ " URL vuelta : "+le.getRetPath());
						tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "URL de regreso tras reenvío a Página de Logon = "+back);
					}
					throw le;
				}	
				catch (Q70AuthorizationException e0)
				{
					if (tr.isTraceActive())
					{
						tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "El usuario no tiene autorización para la Operación de Presentación "+operacionPresentacion);
					}
					throw e0;
					//throw new Q70AuthorizationException(this.getClass().toString(),"processFuncionAutorizacion","El usuario no tiene autorización para la Operación de Presentación  "+operacionPresentacion,e0);
				}
				catch (Q70SeguridadException e1)
				{
					if (tr.isTraceActive())
					{
						tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "Error al comprobar si usuario no tiene autorización para la Operación de Presentación "+operacionPresentacion);
					}
					throw new Q70OperacionDePresentacionException(this.getClass().toString(),"processFuncionAutorizacion","Error al comprobar si usuario no tiene autorización para la Operación de Presentación "+operacionPresentacion,e1);
					
				}
				if (tr.isTraceActive())
				{
					tr.trace(COMPONENTE, Q70TraceLevel.INFO, "El usuario tiene autorización para la Operación de Presentación "+operacionPresentacion);
				}
			}
		} 
		catch (Exception e)
		{
			if (!(e instanceof Q70LogonException))
			{
				if (tr.isTraceActive())
				{
					tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "Error al procesar la autorizacion para la Operación de Presentación "+operacionPresentacion);
				}
				throw new Q70OperacionDePresentacionException(this.getClass().toString(),"processFuncionAutorizacion","Error al procesar la autorizacion para la Operación de Presentación "+operacionPresentacion,e);
			}
			else
			{
				throw new Q70OperacionDePresentacionException(this.getClass().toString(),"processFuncionAutorizacion","El usuario no ha realizado LogOn para la Operación de Presentación "+operacionPresentacion,e);
			}
		}
	}
	
	protected void processSecureId(HttpServletRequest request,Q70PasosOPMapping pasosOPMapping,Q70ContextoEJIE contexto,String operacionPresentacion, String aplicacion) throws Q70FrameworkException
	{
		String back = null;
		String secureId = null;
		
		if (tr.isTraceActive())
		{
			tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Comprobando autorización SecureID para ejecutar la Operación de Presentación "+operacionPresentacion);
		}
		try
		{
			secureId=pasosOPMapping.getSecureId();
			if (null == secureId)
			{
				if (tr.isTraceActive())
				{
					tr.trace(COMPONENTE, Q70TraceLevel.INFO, "La operación de presentación "+operacionPresentacion+" no tiene SecureID de autorización (no requiere logon).");
				}
			}
			else
			{
				if ("".equals(secureId)){
					if (tr.isTraceActive())
					{
						tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "El SecureId esta en blanco para la Operacion de Presentacion"+operacionPresentacion);
					}
					throw new Q70FrameworkException(COMPONENTE,this.getClass().toString(),"processSecureId","El SecureId esta en blanco para la Operacion de Presentacion "+operacionPresentacion,null); 
				}
				if (tr.isTraceActive())
				{
					tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "SecureID de autorización para la Operación de Presentación "+operacionPresentacion+": "+secureId);
				}
				//Comprobamos que existe la información de seguridad de usuario y si es posible se crea.
				Q70InformacionSeguridadUsuario informacionSeguridadUsuario = processSeguridadUsuario(request, operacionPresentacion, contexto);
				//Llamamos al Gestor de Seguridad para comprobar si tiene autorización con el secureId
				try
				{
					Q70GestorSeguridad.getSingleton().checkAuthorization(informacionSeguridadUsuario,aplicacion, secureId);
				}
				catch (Q70LogonException e)
				{
					back = RequestUtils.requestURL(request).toString();
					if (tr.isTraceActive())
					{
						tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "El usuario ha sido desconectado durante la Operación de Presentación "+operacionPresentacion);
						tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "URL de regreso tras reenvío a Página de Logon = "+back);
					}
					Q70LogonException le = new Q70LogonException(((Q70LogonException)e).getClase(),((Q70LogonException)e).getMetodo(),((Q70LogonException)e).getMessage(),((Q70LogonException)e).getThrowable());
					le.setRetPath(back);
					if (tr.isTraceActive())
					{
						tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "[Q70LogonException]= Componente : "+le.getComponente()+ " Clase : "+le.getClase()+ " Metodo : "+le.getMetodo()+ " Q70Mensaje : "+le.getMessage()+ " URL vuelta : "+le.getRetPath());
						tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "URL de regreso tras reenvío a Página de Logon = "+back);
					}
					throw le;
				}	
				catch (Q70AuthorizationException e0)
				{
					if (tr.isTraceActive())
					{
						tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "El usuario no tiene SecureID para la Operación de Presentación "+operacionPresentacion);
					}
					throw e0;
					//throw new Q70AuthorizationException(this.getClass().toString(),"processSecureId","El usuario no tiene SecureId para la Operación de Presentación  "+operacionPresentacion,e0);
	
				}
				catch (Q70SeguridadException e1)
				{
					if (tr.isTraceActive())
					{
						tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "Error al comprobar si usuario no tiene SecureId para la Operación de Presentación "+operacionPresentacion);
					}
					throw new Q70OperacionDePresentacionException(this.getClass().toString(),"processSecureId","Error al comprobar si usuario no tiene SecureId para la Operación de Presentación "+operacionPresentacion,e1);
					
				}
				if (tr.isTraceActive())
				{
					tr.trace(COMPONENTE, Q70TraceLevel.INFO, "El usuario tiene SecureId para la Operación de Presentación "+operacionPresentacion);
				}
			}
		} 
		catch (Exception e)
		{
			if (!(e instanceof Q70LogonException))
			{
				if (tr.isTraceActive())
				{
					tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "Error al procesar el SecureId para la Operación de Presentación "+operacionPresentacion);
				}
				throw new Q70OperacionDePresentacionException(this.getClass().toString(),"processSecureId","Error al procesar el SecureId para la Operación de Presentación "+operacionPresentacion,e);
			}
			else
			{
				throw new Q70OperacionDePresentacionException(this.getClass().toString(),"processSecureId","El usuario no ha realizado LogOn para la Operación de Presentación "+operacionPresentacion,e);
			}
		}
	}
 

	/**
	 * Comprueba que existe la información de seguridad de usuario en el contexto. Si no es asi intenta crearla.
	 * Se iniciliaza dicha informacion en caso necesario. 
	 * Devuelve el objeto de seguridad por si es necesario tratarlo.
	 * 
	 * @param request Contiene las cookies devueltas por xl-nets con la informacion de seguridad
	 * @param operacionPresentacion Para las trazas, meramente informativo 
	 * @param contexto Donde reside el atributo que maneja la seguridad del usuario
	 * @return Q70InformacionSeguridadUsuario
	 * 
	 * @throws Exception
	 */
	private Q70InformacionSeguridadUsuario processSeguridadUsuario(HttpServletRequest request, String operacionPresentacion, Q70ContextoEJIE contexto) throws Exception {
		Q70InformacionSeguridadUsuario informacionSeguridadUsuario;
		if (null == contexto.get(es.ejie.frmk.infraestructura.seguridad.Q70Constantes.SEGURIDAD_USUARIO))
		{
			if (tr.isTraceActive())
			{
				tr.trace(COMPONENTE, Q70TraceLevel.INFO, "No existe Informacion de seguridad de usuario.");
			}
			
			//Si no existe, se pide al Gestor de Seguridad que cree la info de seguridad de usuario			
			informacionSeguridadUsuario = crearInformacionSeguridadUsuario(request, operacionPresentacion);
			
			//Se deposita la info de seguridad de usuario en el contexto de usuario			
			contexto.set(es.ejie.frmk.infraestructura.seguridad.Q70Constantes.SEGURIDAD_USUARIO ,informacionSeguridadUsuario);
			if (tr.isTraceActive())
			{
				tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Información de seguridad de usuario cargada en Contexto de Usuario");
			}
		}
		else
		{
			if (tr.isTraceActive())
			{
				tr.trace(COMPONENTE, Q70TraceLevel.INFO, "Existe Informacion de seguridad de usuario en el Contexto de Usuario.");
			}
			informacionSeguridadUsuario = (Q70InformacionSeguridadUsuario)contexto.get(es.ejie.frmk.infraestructura.seguridad.Q70Constantes.SEGURIDAD_USUARIO);
			
			if (tr.isTraceActive())
			{
				tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Información de seguridad de usuario recuperada del Contexto de Usuario");
			}
		}
		
		//Comprobamos que Q70InformacionSeguridadUsuario esté inicializado.
		if (!Q70GestorSeguridad.getSingleton().isInitialized(informacionSeguridadUsuario))
		{
			if (tr.isTraceActive())
			{
				tr.trace(COMPONENTE, Q70TraceLevel.INFO, "Reconstruyendo la Informacion de seguridad de usuario por no estar inicializado.");
			}
			Q70GestorSeguridad.getSingleton().rebuildUserSecurityInfo(informacionSeguridadUsuario,request);
		} 
							
		if (tr.isTraceActive())
		{
			tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Informacion de seguridad de usuario:" + informacionSeguridadUsuario.toString() );
		}
		return informacionSeguridadUsuario;
	}
	
	/**
	 * Método que colabora con el Gestor de Seguridad para crear la información de seguridad de usuario.
	 * <p>
	 * Lanzará una excepción de tipo <code>Q70LogonException</code> si el usuario no anónimo no está autenticado 
	 * en el sistema.
	 * @param <code>HttpServletRequest</code> Petición a procesar
	 * @param <code>operacionPresentacion</code> Nombre de la Operación de Presentación 
	 * @return <code>Q70InformacionSeguridadUsuario</code>
	 * @throws <code>Exception</code>
	 */
	protected Q70InformacionSeguridadUsuario crearInformacionSeguridadUsuario (HttpServletRequest request, String operacionPresentacion) throws Exception
	{
		try
		{
			return crearInformacionSeguridadUsuario(request);
		}
		catch (Exception e1)
		{
			if (tr.isTraceActive())
			{
				tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "El usuario no ha realizado LogOn correctamente para la Operación de Presentación "+operacionPresentacion);
			}
			if (e1 instanceof Q70LogonException)
			{
				String back = RequestUtils.requestURL(request).toString();
				if (tr.isTraceActive())
				{
					tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "El usuario no ha realizado LogOn correctamente para la Operación de Presentación "+operacionPresentacion);
					tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "URL de regreso tras reenvío a Página de Logon = "+back);
				}
				Q70LogonException le = new Q70LogonException(((Q70LogonException)e1).getClase(),((Q70LogonException)e1).getMetodo(),((Q70LogonException)e1).getMessage(),((Q70LogonException)e1).getThrowable());
				le.setRetPath(back);
				if (tr.isTraceActive())
				{
					tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "[Q70LogonException]= Componente : "+le.getComponente()+ " Clase : "+le.getClase()+ " Metodo : "+le.getMetodo()+ " Q70Mensaje : "+le.getMessage()+ " URL vuelta : "+le.getRetPath());
					tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "URL de regreso tras reenvío a Página de Logon = "+back);
				}
				throw new Q70OperacionDePresentacionException(this.getClass().toString(),"processFuncionAutorizacion","El usuario no ha realizado LogOn para la Operación de Presentación "+operacionPresentacion,le);
			}				
			else
			{
				throw new Q70OperacionDePresentacionException(this.getClass().toString(),"processFuncionAutorizacion","Problemas con la creación de información de Seguridad de Usuario para la Operación de Presentación "+operacionPresentacion,e1);
			}
	
		}
	}

	private Q70InformacionSeguridadUsuario crearInformacionSeguridadUsuario(HttpServletRequest request) throws Q70SeguridadException, Q70LogonException {
		Q70InformacionSeguridadUsuario informacionSeguridadUsuario = Q70GestorSeguridad.getSingleton().createSecurityUserInfo(request);
		if (tr.isTraceActive())
		{
			tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Información de seguridad de usuario creada ="+	informacionSeguridadUsuario.getClass().getName());
		}
		if (!Q70GestorSeguridad.getSingleton().isInitialized(informacionSeguridadUsuario))
		{
			if (tr.isTraceActive())
			{
				tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Información de seguridad no inicializada.");
			}
		}
		else
		{ 
			if (tr.isTraceActive())
			{
				tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Información de seguridad inicializada.");
			}
		}	
		return informacionSeguridadUsuario;
	}
	
	/**
	 * Método que inicializa los contextos y organiza su jerarquía para un usuario.
	 * <p> 
	 * Mediante colaboración con el componente Gestor de Sesión y Datos, creará el contexto 
	 * de Operación de Presentación y los Contextos Globales, teniendo en cuenta la información 
	 * de seguridad de usuario para crear contextos anónimos o no.
	 * Una vez creados los contextos, los encadena en sentido ascendente para que su información quede disponible
	 * para el usuario.
	 * 
	 * @param <code>aplicacion</code> Nombre la Aplicación actual
	 * @param <code>operacionPresentacion</code> Nombre la Operación de Presentación actual
	 * @param <code>Q70ContextoEJIE</code> Contexto genérico
	 * @param <code>ActionMapping</code> Configuración de pasos de Operación de Presentación
	 * @param <code>HttpServletRequest</code> Petición a procesar
	 * @param <code>HttpServletResponse</code> Respuesta a crear
	 * @return <code>Q70ContextoEJIE</code>
	 * @throws <code>FrameworkException</code>
	 */
	private Q70ContextoEJIE processInicializacionContextos(String aplicacion, String operacionPresentacion, Q70ContextoEJIE contexto, ActionMapping mapping, HttpServletRequest request, HttpServletResponse response) throws Q70FrameworkException
	{
		String textomensaje = "crear contexto operacion";
		Q70SesionDatos sesionDatos = Q70SesionDatos.getSingleton();

		//Si existe un contexto, es que no se quieren crear los contextos de operacion de presentacion y el de aplicacion usuario
		List listaContextosAnteriores = null;
		if ( contexto == null ){
			//Creación de nuevo contexto
			contexto = sesionDatos.crearContextoOperacion(getEstructuraDeContexto(mapping), operacionPresentacion);
		}else{
			listaContextosAnteriores = ((Q70ContextoJerarquicoEJIE)contexto).getContextoLista();
		}
				
		//Obtengo la información de seguridad de usuario para poder crear los contextos globales
		//Añadir lista de antecesores
		List listaContextos = new ArrayList(6);
		String idUsuario = null;
		String dpto = null;
		String strAplicacionGlobal = null;
		String grupoAplicacion = null;
		try
		{
			textomensaje = "crear contexto aplicacion global";
			//Parte del nombre del fichero de configuracion para un contexto de aplicacion global
			strAplicacionGlobal = (String)request.getSession().getServletContext().getInitParameter(Q70GestorArranqueConfiguracion.STR_ID_APLICACION_GLOBAL);
			
			//Primero obtengo la función de autorización
			String funcionAutorizacion = null;
			Q70DatosOPConfig datosOPConfig = (Q70DatosOPConfig)request.getSession().getServletContext().getAttribute(Q70DatosOPPlugIn.DATOSOP_KEY+operacionPresentacion);
			if (null != datosOPConfig)
			{
				textomensaje = "obtener funcion autorizacion";
				funcionAutorizacion = datosOPConfig.getFuncionAutorizacion();
			}
			
			Q70InformacionSeguridadUsuario informacionSeguridadUsuario = null;
			
			//Se trata de un usuario que NO NECESITA estar LOGEADO.
			if (null == funcionAutorizacion)
			{
				//Se intenta crear la informacion de seguridad usuario, 
				// si es posible entonces es que NO se trata de un usuario ANONIMO.
				try {
					informacionSeguridadUsuario = crearInformacionSeguridadUsuario(request);
				} catch (Q70LogonException e) {
					//Si da esta excepcion es que no existe un usuario LOGEADO, 
					// y por tanto, se trata de un usuario ANONIMO.
				}
				
				//Se trata de un usuario que NO NECESITA estar LOGEADO.
				if (null == informacionSeguridadUsuario){
					//Contextos para usuario por defecto
					if (tr.isTraceActive())
					{
						tr.trace(COMPONENTE, Q70TraceLevel.INFO, "La operación de presentación "+operacionPresentacion+" no tiene función de autorización (no requiere logon).");
					}
					//Creación de contextos globales para el usuario por defecto.
					if (tr.isTraceActive())
					{
						tr.trace(COMPONENTE, Q70TraceLevel.INFO, "Creación de contextos globales para el usuario por defecto.");
					}
					textomensaje = "añadir contexto basico aplicacion " + aplicacion;
					// Añadir contextbasico para aplicacion con xml de configuracion de ruta
					try
					{
						if (listaContextosAnteriores == null) {
							//Es un contexto nuevo
							listaContextos.add(sesionDatos.crearContexto(Q70SesionDatos.CTX_APLICACION,aplicacion+"_aplicacion",Q70Constantes.XML_APLICACION_FILE_SUFIX));				
						} else {
							//Es un contexto que ya existe, se añade el contexto de aplicacion del contexto anterior
							listaContextos.add(listaContextosAnteriores.get(0));				
						}
					}
					catch (NullPointerException npe)
					{
						if (tr.isTraceActive())
						{
							tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "Asegurese de que la ruta para el parametro 'contextoAplicacion' es correcta:\nen el fichero web.xml\n<param-name>contextoAplicacion</param-name>\n<param-value>WEB-INF/aplic/...</param-value>\n");
						}
						throw npe;
					}
					grupoAplicacion = rp.getServlet().getServletConfig().getInitParameter(Q70Constantes.GRUPO_APLIC_KEY);
					idUsuario = recuperarIdUsuarioAnonimo(request, response);
					
					textomensaje = "añadir contexto grupo aplicacion " + grupoAplicacion;
					if ( grupoAplicacion != null){
						listaContextos.add(sesionDatos.crearContextoGrupoAplicacion(sesionDatos.getIdContextoGrupoAplicacion(idUsuario, grupoAplicacion), Q70Constantes.XML_GRUPO_APLIC_FILE_PREFIX+grupoAplicacion+Q70Constantes.XML_GRUPO_APLIC_FILE_SUFIX));
					}
					textomensaje = "crear contexto usuario " + idUsuario;
					listaContextos.add(sesionDatos.crearContextoSesionUsuario(idUsuario, Q70Constantes.XML_USER_FILE));
					// Metodo de ayuda para inicializar contextos globales del sesionDatos
					textomensaje = "crear contexto aplicacion global " + strAplicacionGlobal;
					listaContextos.add(sesionDatos.getContextoGlobal(Q70SesionDatos.CTX_GLOBAL_APLICACIONGLOBAL, strAplicacionGlobal));
					textomensaje = "crear contexto departamento " + Q70Constantes.DEFAULT_DPTO;
					listaContextos.add(sesionDatos.getContextoGlobal(Q70SesionDatos.CTX_GLOBAL_DEPARTAMENTO, Q70Constantes.DEFAULT_DPTO));
					textomensaje = "crear contexto entidad " + rp.getServlet().getServletConfig().getInitParameter(Q70Constantes.ENTIDAD_KEY);
					listaContextos.add(sesionDatos.getContextoGlobal(Q70SesionDatos.CTX_GLOBAL_ENTIDAD, rp.getServlet().getServletConfig().getInitParameter(Q70Constantes.ENTIDAD_KEY)));
					textomensaje = "crear contexto sistema tecnico";
					//listaContextos.add(sesionDatos.getContextoGlobal(Q70SesionDatos.CTX_GLOBAL_SISTEMA_TECNICO, request.getServerName()));
					listaContextos.add(sesionDatos.getContextoGlobal(Q70SesionDatos.CTX_GLOBAL_SISTEMA_TECNICO, Q70GestorArranqueConfiguracion.getGlobalProperty(Q70Constantes.SISTEMA_TECNICO)));
				}
			}
			//Se trata de un usuario que está o que debe estar LOGEADO.
			if (null != funcionAutorizacion || informacionSeguridadUsuario != null)
			{
				textomensaje = "crear informacion de seguridad";
				if (null == informacionSeguridadUsuario){
					informacionSeguridadUsuario = crearInformacionSeguridadUsuario(request, operacionPresentacion);
				}
				//Creación de contextos globales para un usuario especifico.
				if (tr.isTraceActive())
				{
					tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Creación de contextos globales para el usuario "+Q70GestorSeguridad.getSingleton().getSessionId(informacionSeguridadUsuario));
				}
				// Añadir contextbasico para aplicacion con xml de configuracion de ruta
				try
				{
					textomensaje = "añadir contexto basico de aplicacion";
					listaContextos.add(sesionDatos.crearContexto(Q70SesionDatos.CTX_APLICACION,aplicacion+"_aplicacion",Q70Constantes.XML_APLICACION_FILE_SUFIX));				
				}
				catch (NullPointerException npe)
				{
					if (tr.isTraceActive())
					{
						tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "Asegurese de que la ruta para el parametro 'contextoAplicacion' es correcta:\nEn el web.xml\n<param-name>contextoAplicacion</param-name>\n<param-value>WEB-INF/configuradores/aplicacion/contexto-aplicacion.xml</param-value>\n");
					}
					throw npe;
				}
				textomensaje = "obtener identificador usuario";
				grupoAplicacion = rp.getServlet().getServletConfig().getInitParameter(Q70Constantes.GRUPO_APLIC_KEY);
				idUsuario = Q70GestorSeguridad.getSingleton().getSessionId(informacionSeguridadUsuario);
				if ( grupoAplicacion != null){
					textomensaje = "crear y añadir contexto grupo aplicacion " + grupoAplicacion;
					listaContextos.add(sesionDatos.crearContextoGrupoAplicacion(sesionDatos.getIdContextoGrupoAplicacion(idUsuario, grupoAplicacion), Q70Constantes.XML_GRUPO_APLIC_FILE_PREFIX+grupoAplicacion+Q70Constantes.XML_GRUPO_APLIC_FILE_SUFIX));
				}
				textomensaje = "crear y añadir contexto sesion usuario " + idUsuario;
				listaContextos.add(sesionDatos.crearContextoSesionUsuario(idUsuario, Q70Constantes.XML_USER_FILE));
				// Metodo de ayuda para inicializar contextos globales del sesionDatos
				textomensaje = "crear y añadir contexto aplicacion global " + strAplicacionGlobal;
				listaContextos.add(sesionDatos.getContextoGlobal(Q70SesionDatos.CTX_GLOBAL_APLICACIONGLOBAL, strAplicacionGlobal));
				textomensaje = "obtener departamento ";
				dpto = Q70GestorSeguridad.getSingleton().getSessionOrganization(informacionSeguridadUsuario);
				textomensaje = "crear y añadir contexto departamento " + dpto;
				
				/* 11/10/2005 - JVP
				 * Controlamos que no da error al añadir el contexto del departamento
				 * Si no está definido, creamos el contexto de departamento anonimo
				 */
				try{
					//if (null != dpto && dpto.trim().length()!= 0)
					//{	
					listaContextos.add(sesionDatos.getContextoGlobal(Q70SesionDatos.CTX_GLOBAL_DEPARTAMENTO, dpto));
					//}
				}catch(Exception exDpto){
					textomensaje=textomensaje.concat(" - suponemos contexto anonimo");
					if (tr.isTraceActive())
					{
						tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "ERROR al " + textomensaje + " Procedemos a utilizar el departamento anonimo ");
					}
					//Sacamos una traza por el log de incidencias ya que se trata de un error de configuracion
					Q70LogIncidencias logInc = Q70LogIncidencias.getSingleton();
					if (logInc.isEnabled())
					{
						logInc.log(exDpto, COMPONENTE);
					}
					dpto = Q70Constantes.DEFAULT_DPTO;
					listaContextos.add(sesionDatos.getContextoGlobal(Q70SesionDatos.CTX_GLOBAL_DEPARTAMENTO, dpto));
				}
				/* 11/10/2005 - JVP
				 * Fin de modificacion
				 * */
				textomensaje = "crear y añadir contexto entidad " + rp.getServlet().getServletConfig().getInitParameter(Q70Constantes.ENTIDAD_KEY);
				listaContextos.add(sesionDatos.getContextoGlobal(Q70SesionDatos.CTX_GLOBAL_ENTIDAD, rp.getServlet().getServletConfig().getInitParameter(Q70Constantes.ENTIDAD_KEY)));
				//listaContextos.add(sesionDatos.getContextoGlobal(Q70SesionDatos.CTX_GLOBAL_SISTEMA_TECNICO, request.getServerName()));
				textomensaje = "crear y añadir contexto sistema tecnico";
				listaContextos.add(sesionDatos.getContextoGlobal(Q70SesionDatos.CTX_GLOBAL_SISTEMA_TECNICO, Q70GestorArranqueConfiguracion.getGlobalProperty(Q70Constantes.SISTEMA_TECNICO)));
			}
		}
		catch (Exception e1) {
			if (tr.isTraceActive())
			{
				tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "ERROR al " + textomensaje);
			}
			//Q70ContextosEnMemoriaManejador.removeContexto(Q70SesionDatos.CTX_GLOBAL_SISTEMA_TECNICO, Q70GestorArranqueConfiguracion.getGlobalProperty(Q70Constantes.SISTEMA_TECNICO));
			//Q70ContextosEnMemoriaManejador.removeContexto(Q70SesionDatos.CTX_GLOBAL_ENTIDAD, rp.getServlet().getServletConfig().getInitParameter(Q70Constantes.ENTIDAD_KEY));
			//Q70ContextosEnMemoriaManejador.removeContexto(Q70SesionDatos.CTX_GLOBAL_DEPARTAMENTO, dpto);
			Q70ContextosEnMemoriaManejador.removeContexto(Q70SesionDatos.CTX_SESION_USUARIO, idUsuario);
			//Q70ContextosEnMemoriaManejador.removeContexto(Q70SesionDatos.CTX_GLOBAL_APLICACIONGLOBAL, strAplicacionGlobal);
			Q70ContextosEnMemoriaManejador.removeContexto(Q70Constantes.XML_GRUPO_APLIC_FILE_PREFIX+grupoAplicacion+Q70Constantes.XML_GRUPO_APLIC_FILE_SUFIX, sesionDatos.getIdContextoGrupoAplicacion(idUsuario, grupoAplicacion));
			// TODO Jgrey Mirar si hay que remover estos contextos de sesion usuario y grupo aplicacion cuando hay excepcion
			throw new Q70OperacionDePresentacionException(this.getClass().toString(),"processInicializacionContextos","ERROR al " + textomensaje,e1);
		}
		//Añadimos los contextos globales al contexto
		contexto = sesionDatos.addListaContextos(contexto, listaContextos);
		return contexto;
	}

	/**
	 * Devuelve el identificativo del usuario anonimo para esta sesion.
	 * Tiene que comprobar si existe un usuario anonimo ya creado para esta sesión, 
	 * investigando la existencia de la cookie al efecto en el navegador de usuario.
	 * Si no existe cookie, entonces se crea una nueva con el id de la HttpSession actual, 
	 * construyendose el id de usuario anonimo y fijandodose esta cookie en el navegador 
	 * para su uso futuro por otras aplicaciones en este servidor de aplicaciones o en otro.
	 * 
	 * Hay que controlar el tamaño maximo de id. de usuario para que no supere la columna de
	 * la tabla de bbdd de sesion usuario (teniendo en cuenta al grupo de aplicaciones).
	 * 
	 * @param request
	 * @param response
	 * @return Devuelve el identificativo del usuario anonimo para esta sesion.
	 */
	private String recuperarIdUsuarioAnonimo(HttpServletRequest request, HttpServletResponse response) {
		String idUsuario = null;

        Cookie[] cookies = request.getCookies();
        if (cookies != null){
            for (int i = 0; i < cookies.length; i++) {
    			if (cookies[i].getName().equals(Q70Constantes.DEFAULT_USER)){
    				idUsuario = cookies[i].getValue();
    				break;
    			}
    		}
        }
        if (null == idUsuario) {
    		idUsuario = Q70Constantes.DEFAULT_USER + request.getSession().getId();
    		idUsuario = StringUtils.substring(idUsuario, 0, 75);
    		Cookie userCookie = new Cookie(Q70Constantes.DEFAULT_USER, idUsuario);
    		userCookie.setPath("/");
    		userCookie.setMaxAge(-1);
    		response.addCookie(userCookie);
        }
		return idUsuario;
	}
	
	/**
	 * Método que indica si los contexto anónimos siguen siendo válidos para la petición actual de un usuario.
	 * <p>
	 * No serán válidos contextos anónimos cuando estemos tratando un cambio de Operación de Presentación
	 * a una que tiene función de autorización (por tanto, no anónima) y provenimos de otra anónima.
	 * En ese caso, habrá que reconstruir la jerarquía completa de contextos, ya que la estructura anónima ya no será
	 * válida para el usuario.
	 * 
	 * @param <code>HttpServletRequest</code> Petición a procesar
	 * @param <code>Q70ContextoEJIE</code> Contexto genérico
	 * @param <code>operacionPresentacion actual</code> Operación de Presentación actual
	 * @return <code>true</code> -> si es valido
	 * 		   <code>false</code> -> si hay que reconstruir los contextos
	 * @throws <code>FrameworkException</code> 
	 */
	private boolean esValidoContextoAnonimo(HttpServletRequest request, Q70ContextoEJIE contexto, String operacionPresentacion) throws Q70FrameworkException
	{
		boolean valido = true;
		try
		{
			if (tr.isTraceActive())
			{
				tr.trace(COMPONENTE, Q70TraceLevel.INFO, "Comprobando si el idUsuario de los contextos globales era anonimo y la operación de presentación actual requiere autorización");
			}
			//Si el idUsuario de los contextos globales era anonimo.
			if (-1!=Q70SesionDatos.getSingleton().getContexto(contexto,Q70SesionDatos.CTX_SESION_USUARIO).getIdContexto().indexOf(Q70Constantes.DEFAULT_USER))
			{
				//Si la operación de presentaciónm actual requiere autorización
				String funcionAutorizacion = null;
				Q70DatosOPConfig datosOPConfig = (Q70DatosOPConfig)request.getSession().getServletContext().getAttribute(Q70DatosOPPlugIn.DATOSOP_KEY+operacionPresentacion);
				if (null != datosOPConfig)
				{
					funcionAutorizacion = datosOPConfig.getFuncionAutorizacion();
				}
				if (null != funcionAutorizacion)
				{
					if (tr.isTraceActive())
					{
						tr.trace(COMPONENTE, Q70TraceLevel.INFO, "El idUsuario de los contextos globales era anonimo y la operación de presentación actual requiere autorización.");
					}
					valido = false;
				}	
			}
		}
		catch (Exception e) {
			if (tr.isTraceActive())
			{
				tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "ERROR comprobando si el idUsuario de los contextos globales era anónimo y la operación de presentación actual requiere autorización.");
			}
			throw new Q70OperacionDePresentacionException(this.getClass().toString(),"esValidoContextoAnonimo","ERROR comprobando si el idUsuario de los contextos globales era anonimo y la operación de presentación actual requiere autorización.",e);
		}
		return valido;
	}
/**
 * Método que ejecuta Mapas sobre Contextos colaborando con el Gestor de Mapas.
 * <p>
 * @param <code>mapping</code>Configuración de pasos de una Operación de Presentación
 * @param <code>session</code>Sesión del usuario
 * @throws Q70FrameworkException
 */	
	private void processMapeoContexto(Q70PasosOPMapping mapping, HttpSession session) throws Q70FrameworkException
	{
		if (null != mapping.getMapa() && (!mapping.getMapa().trim().equals("")))
		{
			// Tenemos en cuenta si es un action de apilamiento de suboperación,
			// en este caso, el mapeo ha sido realizado en el apilamiento de la
			// estructura de dialogo
			if (null == mapping.getSubOpRetPath() || (mapping.getSubOpRetPath().trim().equals("")))
			{ 
				if (tr.isTraceActive())
				{
					tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Procesando mapeo para el contexto. Mapeo: "+mapping.getMapa());
				}
				try {
					// Recuperamos el contexto para mapearlo
					Q70ContextoEJIE contexto = (Q70ContextoEJIE)session.getAttribute(Q70Constantes.CONTEXT);
					// Realizamos el mapeo
					Q70GestorMapeador.getSingleton().mapObjects(mapping.getMapa(), contexto, contexto);
					// Almacenamos el contexto
					setContextoEnHttpSession(session, contexto);
				} catch (Exception e) {
					if (tr.isTraceActive())
					{
						tr.trace(COMPONENTE, Q70TraceLevel.ERROR, "ERROR Procesando mapeo para el contexto. Mapeo: "+mapping.getMapa());
					}
					throw new Q70OperacionDePresentacionException(this.getClass().toString(),"processMapeoContexto","ERROR Procesando mapeo para el contexto. Mapeo: "+mapping.getMapa(),e);
				}
			}
		}
	}
/**
 * Método que inicializa atributos determinados de contextos.
 * <p>
 * La configuración de un paso de Operación de Presentación puede presentar una propiedad "erase" que
 * enumera atributos que se desea que se inicialicen a null una vez ejecutado el paso de Operación
 * @param <code>mapping</code>Configuración de pasos de una Operación de Presentación
 * @param <code>session</code>Sesión del usuario
 * @throws Q70FrameworkException
 */	
	private void processInicializacionContexto(Q70PasosOPMapping mapping, HttpSession session) throws Q70FrameworkException
	{
		if (null != mapping.getErase() && (!mapping.getErase().trim().equals("")))
		{
			if (tr.isTraceActive())
			{
				tr.trace(COMPONENTE, Q70TraceLevel.DEBUG, "Procesando inicialización a null para atributos del contexto. Atributos: "+mapping.getErase());
			}
			
			// Recuperamos el contexto para mapearlo
			Q70ContextoEJIE contexto = (Q70ContextoEJIE)session.getAttribute(Q70Constantes.CONTEXT);
			//Recuperamos los atributos a inicializar
			StringTokenizer tokens = new StringTokenizer(mapping.getErase(),",");
			String atributo = null;
			while (tokens.hasMoreTokens())
			{
				try {
					atributo = tokens.nextToken().trim();
					// Inicializamos a null cada atributo 
					contexto.set(atributo,null);
					if (tr.isTraceActive())
					{
						tr.trace(COMPONENTE, Q70TraceLevel.INFO, atributo+" = null");
					}
				} catch (Exception e) {
					if (tr.isTraceActive())
					{
						tr.trace(COMPONENTE, Q70TraceLevel.WARN, "No se ha podido inicializar a null el atributo de contexto "+atributo);
					}
				}
			}
			// Almacenamos el contexto
			setContextoEnHttpSession(session, contexto);
		}
	}

	private void setContextoEnHttpSession(HttpSession session, Q70ContextoEJIE contexto) {
		session.setAttribute(Q70Constantes.CONTEXT, contexto);
		Object idContextoAux = null;
		if (contexto != null) {
			Q70ContextoEJIE contextoUsuario = Q70SesionDatos.getSingleton().getContexto(contexto, Q70SesionDatos.CTX_SESION_USUARIO);
			if (contextoUsuario != null) {
				idContextoAux = contextoUsuario.getIdContexto();
			}
		}
		session.setAttribute(Q70Constantes.CONTEXT_ID_USUARIO, idContextoAux);
	}
}
