package es.ejie.frmk.infraestructura.seguridad;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.servlet.http.HttpServletRequest;

import n38a.exe.N38APISesion;
import n38c.exe.N38API;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

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.infraestructura.traza.Q70TraceLevel;
import es.ejie.frmk.infraestructura.traza.Q70TrazaInterface;
import es.ejie.frmk.infraestructura.utilidades.excepciones.Q70UtilidadesExcepcion;
import es.ejie.frmk.infraestructura.utilidades.general.Q70UtilidadesGenerales;
import es.ejie.frmk.infraestructura.utilidades.xml.Q70UtilidadesXML;
import es.ejie.frmk.presentacion.sesiondatos.Q70ContextoEJIE;

/**
 * La clase implementa la funcionalidad del componente <b>Gestor de Seguridad</b> que encapsula la comunicación
 * con el sistema XL-Nets.
 * <P> 
 * Su mecanismo es el siguiente: 
 * <P>
 * cuando una Operación de Presentación necesita controlar la autorización de ejecución, solicitará al contexto de Usuario la información de seguridad del usuario.
 * <ul>
 * <li>Si la información de seguridad no existe en el contexto de usuario, será necesario crearla obteniendo 
 * la información de seguridad de usuario de XL-Nets (<code>n38itemSesion</code>):</li>
 * <ul>
 * <li>Si existe información de sesión, es decir, XL-Nets devuelve un XML de sesión válido, el usuario está autenticado y el proceso continua.</li>
 * <li>Si no existe información de sesión, es decir, XL-Nets devuelve un XML de error, el sistema redirigirá a la página de logon especificada en el fichero de configuración, indicando con el parámetro N38API la dirección de regreso una vez autenticado.</li>
 * </ul>
 * <li>Si la información existe en el contexto, se valida que esté bien formada</li>
 * <ul>
 * <li>si no lo está, se reconstruye la información de seguridad de usuario haciendo una petición a XLNets de información de sesión de usuario.</li>
 * <li>si lo está, se permite continuar el proceso</li>
 * </ul>
 * </ul>
 * Una vez que tenemos el objeto de información de seguridad de usuario en el contexto con la información de la sesión de usuario de XL-Nets, 
 * se solicita la validación de la función de autorización de la operación de presentación. Para ello:
 * <ul>
 * <li>si se ha definido “caching” en la configuración del componente, se comprueba si se dispone ya de la información de autorizaciones para la aplicación :</li>
 * <ul>
 * <li>si no se dispone, se recoge de una vez todas las funciones de autorización del usuario para la aplicación dada (n38itemSeguridad) y se cachéan.</li>
 * <li>si se dispone, continúa</li>
 * </ul>
 * <li>si no se ha definido “caching” se obtienen las autorizaciones de usuario (n38ItemObtenerAutorizacion en XLNets).</li>
 * <li>se chequea la autorización: si no está autorizado se lanza una excepción de seguridad y si es necesario hacer logon se lanza una excepción de logon</li>
 * </ul>
 */
public class Q70GestorSeguridad implements Q70GestorSeguridadInterface, Q70Arrancable {
	private String xmlFile = null;
	private static Q70GestorSeguridad instancia;
	private String logonPage = null;
	private boolean cachearFunciones = false;
	 
	/** 
	 * @see es.ejie.frmk.infraestructura.seguridad.Q70GestorSeguridadInterface#createSecurityApplicationInfo(java.lang.String)
	 */
	public Q70InformacionSeguridadAplicacion createSecurityApplicationInfo(String aplicacion) throws Q70SeguridadException {
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		if(traza.isTraceActive())
			traza.trace(Q70Constantes.ID_COMPONENTE,Q70TraceLevel.INFO, "Crear informacion seguridad Aplicacion");		
		return new Q70InformacionSeguridadAplicacion(aplicacion);
	}
	
	/**
	 * @see es.ejie.frmk.infraestructura.seguridad.Q70GestorSeguridadInterface#destroySession(es.ejie.frmk.infraestructura.seguridad.Q70InformacionSeguridadInterface)
	 */
	public void destroySession(Q70InformacionSeguridadInterface inf) throws Q70SeguridadException{
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		if(traza.isTraceActive())
			traza.trace(Q70Constantes.ID_COMPONENTE,Q70TraceLevel.INFO, "Eliminar sesion");
		N38APISesion n38ApiSesion = new N38APISesion();
		n38ApiSesion.n38APISesionDestruir(getSessionId(inf));
		
	}
	
	/**
	 * @see es.ejie.frmk.infraestructura.seguridad.Q70GestorSeguridadInterface#rebuildAppSecurityInfo(es.ejie.frmk.infraestructura.seguridad.Q70InformacionSeguridadInterface, java.lang.String)
	 */
	public void rebuildAppSecurityInfo(Q70InformacionSeguridadInterface inf, String aplicacion)  throws Q70SeguridadException{
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		if(traza.isTraceActive())
			traza.trace(Q70Constantes.ID_COMPONENTE,Q70TraceLevel.INFO, "Reconstruir informacion seguridad " + inf + " " + aplicacion);		
		((Q70InformacionSeguridadAplicacion)inf).buildSecurityInf(aplicacion);
	}
	
	/**
	 * @see es.ejie.frmk.infraestructura.seguridad.Q70GestorSeguridadInterface#createSecurityUserInfo(javax.servlet.http.HttpServletRequest)
	 */
	public Q70InformacionSeguridadUsuario createSecurityUserInfo(HttpServletRequest req) throws Q70SeguridadException, Q70LogonException{
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		if(traza.isTraceActive())
			traza.trace(Q70Constantes.ID_COMPONENTE,Q70TraceLevel.INFO, "Crear informacion seguridad usuario");		
		Q70InformacionSeguridadUsuario inf = new Q70InformacionSeguridadUsuario(req);
		return inf;
	}
	
	/**
	 * @see es.ejie.frmk.infraestructura.seguridad.Q70GestorSeguridadInterface#rebuildUserSecurityInfo(es.ejie.frmk.infraestructura.seguridad.Q70InformacionSeguridadUsuario, javax.servlet.http.HttpServletRequest)
	 */
	public void rebuildUserSecurityInfo(Q70InformacionSeguridadUsuario inf, HttpServletRequest req)  throws Q70SeguridadException, Q70LogonException{
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		if(traza.isTraceActive())
			traza.trace(Q70Constantes.ID_COMPONENTE,Q70TraceLevel.INFO, "Reconstruir informacion seguridad " + inf);				
		inf.buildSecurityInf(req);
	}
	
	/**
	 * Método que checkea la existencia de un item de seguridad de XLNets.
	 * @param infSeguridad Informacion de seguridad.
	 * @param uidItemSeguridad Identificativo único del item de seguridad.
	 * @throws Q70SeguridadException
	 * @throws Q70LogonException
	 * @throws Q70AuthorizationException
	 */
	public void checkItemSeguridad(Q70InformacionSeguridadInterface infSeguridad, String uidItemSeguridad) throws Q70SeguridadException, Q70LogonException, Q70AuthorizationException {
		Document xmlItemSeguridad = null;
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		if (infSeguridad instanceof Q70InformacionSeguridadAplicacion) {
			if(traza.isTraceActive()) {
				traza.trace(Q70Constantes.ID_COMPONENTE,Q70TraceLevel.INFO, "Checkear item seguridad de aplicación.");
			}
			Q70InformacionSeguridadAplicacion informacionSeguridadAplicacion = (Q70InformacionSeguridadAplicacion)infSeguridad;
			xmlItemSeguridad = informacionSeguridadAplicacion.getToolKit().n38ItemSeguridad(uidItemSeguridad);
		} else if (infSeguridad instanceof Q70InformacionSeguridadUsuario) {
			if(traza.isTraceActive()) {
				traza.trace(Q70Constantes.ID_COMPONENTE,Q70TraceLevel.INFO, "Checkear item seguridad de usuario.");
			}
			Q70InformacionSeguridadUsuario informacionSeguridadUsuario = (Q70InformacionSeguridadUsuario)infSeguridad;
			xmlItemSeguridad = informacionSeguridadUsuario.getToolKit().n38ItemSeguridad(uidItemSeguridad);
		}
		try {
			checkResult(xmlItemSeguridad);
		} catch(Q70SeguridadException e) {
			throw new Q70SeguridadException(this.getClass().getName(), "checkItemSeguridad", "Error al recuperar una instancia de tipos de objeto (XLNets).", e);						
		}
	}
	
	/**
	 * Método que recupera un item de seguridad de XLNets.
	 * @param infSeguridad Informacion de seguridad.
	 * @param uidItemSeguridad Identificativo único del item de seguridad.
	 * @return String Retorna el texto correspondiente al item de seguridad. 
	 * @throws Q70FrameworkException
	 */
	public String getItemSeguridad(Q70InformacionSeguridadInterface infSeguridad, String uidItemSeguridad) throws Q70SeguridadException, Q70LogonException, Q70AuthorizationException {
		Document xmlItemSeguridad = null;
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		if (infSeguridad instanceof Q70InformacionSeguridadAplicacion) {
			if(traza.isTraceActive()) {
				traza.trace(Q70Constantes.ID_COMPONENTE,Q70TraceLevel.INFO, "Checkear item seguridad de aplicación.");
			}
			Q70InformacionSeguridadAplicacion informacionSeguridadAplicacion = (Q70InformacionSeguridadAplicacion)infSeguridad;
			xmlItemSeguridad = informacionSeguridadAplicacion.getToolKit().n38ItemSeguridad(uidItemSeguridad);
		} else if (infSeguridad instanceof Q70InformacionSeguridadUsuario) {
			if(traza.isTraceActive()) {
				traza.trace(Q70Constantes.ID_COMPONENTE,Q70TraceLevel.INFO, "Checkear item seguridad de usuario.");
			}
			Q70InformacionSeguridadUsuario informacionSeguridadUsuario = (Q70InformacionSeguridadUsuario)infSeguridad;
			xmlItemSeguridad = informacionSeguridadUsuario.getToolKit().n38ItemSeguridad(uidItemSeguridad);
		}
		try {
			checkResult(xmlItemSeguridad);
			String filtro = Q70UtilidadesGenerales.replaceString(Q70Constantes.ITEM_SEGURIDAD,"?",uidItemSeguridad);
			 
			return Q70UtilidadesXML.searchDomString(xmlItemSeguridad, filtro);
		} catch(Q70SeguridadException e) {
			throw new Q70SeguridadException(this.getClass().getName(), "getItemSeguridad", "Error al recuperar una instancia de tipos de objeto (XLNets).", e);
		} catch(Q70UtilidadesExcepcion ue) {
			throw new Q70SeguridadException(this.getClass().getName(), "getItemSeguridad", "Se ha producido un error al recuperar el item de seguridad de XLNets.", ue);						
		}
		
	}
	
	/** 
	 * @see es.ejie.frmk.infraestructura.seguridad.Q70GestorSeguridadInterface#checkAuthorization(es.ejie.frmk.infraestructura.seguridad.Q70InformacionSeguridadUsuario, java.lang.String, java.lang.String)
	 */
	public void checkAuthorization(Q70InformacionSeguridadUsuario usuarioInf, String aplicacion, String funcionAutorizacion) throws Q70SeguridadException, Q70AuthorizationException, Q70LogonException {
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		if(traza.isTraceActive())
			traza.trace(Q70Constantes.ID_COMPONENTE,Q70TraceLevel.INFO, "Checkear autorizacion");				
		if(cachearFunciones)
			checkCachedAuthorization(usuarioInf, aplicacion, funcionAutorizacion);
		else
			checkNoCachedAuthorization(usuarioInf, aplicacion, funcionAutorizacion);
	}
	
	/**
	 * Chequeo de Función de Autorización para el caso que las funciones de autorizacion se cacheen.
	 * @param usuarioInf Información de Seguridad del Usuario
	 * @param aplicacion Nombre de la aplicación
	 * @param funcionAutorizacion Función de Autorización de la Operación de Presentación
	 * @throws Q70SeguridadException 
	 * @throws Q70AuthorizationException
	 * @throws Q70LogonException
	 */
	private void checkCachedAuthorization(Q70InformacionSeguridadUsuario usuarioInf, String aplicacion, String funcionAutorizacion) throws Q70SeguridadException, Q70AuthorizationException, Q70LogonException {
		Vector funciones = null;
		if (null!=usuarioInf.getSecurityAuthorizations().get(aplicacion)) {
			funciones = (Vector)usuarioInf.getSecurityAuthorizations().get(aplicacion);
		}
		if (null==funciones || funciones.size()<=0) {
			funciones = getFuncionesAutorizacion(usuarioInf,aplicacion);
			HashMap autorizaciones = usuarioInf.getSecurityAuthorizations();
			if (autorizaciones==null) autorizaciones = new HashMap();
			autorizaciones.put(aplicacion, funciones);
			usuarioInf.setSecurityAuthorizations(autorizaciones);
		}
		if(!funciones.contains(funcionAutorizacion)){
			throw new Q70AuthorizationException(this.getClass().getName(), "checkCachedAuthorization", "Funcion no autorizada", null);						
		}
	}

	/**
	 * Chequeo de Función de Autorización para el caso que las funciones de autorizacion no se cacheen.
	 * @param usuarioInf Información de Seguridad del Usuario
	 * @param aplicacion Información de Seguridad del Usuario
	 * @param funcionAutorizacion Función de Autorización de la Operación de Presentación
	 * @throws Q70SeguridadException
	 * @throws Q70AuthorizationException
	 * @throws Q70LogonException
	 */
	private void checkNoCachedAuthorization(Q70InformacionSeguridadUsuario usuarioInf, String aplicacion, String funcionAutorizacion) throws Q70SeguridadException, Q70AuthorizationException, Q70LogonException {
		try {
			Document xml = (Document)((N38API)usuarioInf.getToolKit()).n38ItemObtenerAutorizacion(funcionAutorizacion);
			checkResult(xml);
		} catch(Q70SeguridadException se) {
			throw new Q70SeguridadException(this.getClass().getName(), "checkNoCachedAuthorization", "Funcion no autorizada", se);						
		}
	}		

	/**
	 * @see es.ejie.frmk.infraestructura.seguridad.Q70GestorSeguridadInterface#getDBUser(es.ejie.frmk.infraestructura.seguridad.Q70InformacionSeguridadUsuario, java.lang.String)
	 */
	public String[] getDBUser(Q70InformacionSeguridadUsuario usuarioInf, String recurso) throws Q70SeguridadException, Q70AuthorizationException, Q70LogonException {
		String[] retorno = new String[2];
		Document xml = (Document)((N38API)usuarioInf.getToolKit()).n38ItemSeguridad(recurso);
		checkResult(xml);
		try{
			String miUsuarioPasswordOracle = Q70UtilidadesXML.searchDomString(xml, Q70Constantes.PATH_DB_USER_PASS);
			StringTokenizer infConexion = new StringTokenizer(miUsuarioPasswordOracle,"#",false);
			retorno[0] = infConexion.nextToken();
			retorno[1] = infConexion.nextToken();
			retorno[2] = infConexion.nextToken();		
		}catch(NoSuchElementException nse){
			throw new Q70SeguridadException(this.getClass().getName(), "getDBUser", "No encontrado usuario/password solicitados", nse);
		}catch(Q70UtilidadesExcepcion ue){
			throw new Q70SeguridadException(this.getClass().getName(), "getDBUser", "No encontrado usuario/password solicitados", ue);
		}		
		return retorno;					
	}
	
	/**
	 * @see es.ejie.frmk.infraestructura.seguridad.Q70GestorSeguridadInterface#getCustomTagDisplayMode(es.ejie.frmk.infraestructura.seguridad.Q70InformacionSeguridadUsuario, java.lang.String, java.lang.String)
	 */
	public int getCustomTagDisplayMode(Q70InformacionSeguridadUsuario usuarioInf, String aplicacion, String secureId) throws Q70SeguridadException, Q70LogonException{
		try {
			checkItemSeguridad(usuarioInf,secureId);
		} catch (Q70AuthorizationException e) {
			return 2;
		}
		return 0;
	}	

	/**
	 * @see es.ejie.frmk.infraestructura.seguridad.Q70GestorSeguridadInterface#getSessionSecurityInf(es.ejie.frmk.infraestructura.seguridad.Q70InformacionSeguridadInterface, java.lang.String)
	 */
	public Object getSessionSecurityInf(Q70InformacionSeguridadInterface sesionInf, String parametro) throws Q70SeguridadException{
		return sesionInf.getSessionSecurityInf(parametro);		
	}
	
	/**
	 * @see es.ejie.frmk.infraestructura.seguridad.Q70GestorSeguridadInterface#isInitialized(es.ejie.frmk.infraestructura.seguridad.Q70InformacionSeguridadInterface)
	 */
	public boolean isInitialized(Q70InformacionSeguridadInterface sesionInf){
		try{
			if(getSessionId(sesionInf) == null)
				return false;
		}catch(Q70SeguridadException se){
			return false;
		}
		return true;
	}	
	
	/**
	 * Analiza la respuesta de una peticion a XL-Nets para ver si ha sido correcta.
	 * @exception Q70SeguridadException si XL-Nets devolvió error.
	 * @param doc
	 * @throws Q70SeguridadException
	 * @throws Q70AuthorizationException
	 * @throws Q70LogonException	 
	 */
	private void checkResult(Document doc) throws Q70SeguridadException, Q70AuthorizationException, Q70LogonException{
		String code = "";
		String motivo = "";
		String descripcion = "";
		String ErrorTraza = "";
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		
		if(traza.isTraceActive())
			traza.trace(Q70Constantes.ID_COMPONENTE,Q70TraceLevel.INFO, "Checkear xml devuelto");				
		try{
			if(Q70UtilidadesXML.searchDomNode(doc,Q70Constantes.PATH_CHECK_ERROR) != null){
				code = Q70UtilidadesXML.searchDomString(doc,Q70Constantes.PATH_CHECK_ERROR + Q70Constantes.PATH_CODIGO); 
			}
			else
				if(Q70UtilidadesXML.searchDomNode(doc,Q70Constantes.PATH_CHECK_INFO) != null){
					code = Q70UtilidadesXML.searchDomString(doc,Q70Constantes.PATH_CHECK_INFO + Q70Constantes.PATH_CODIGO);				
				}
				else
					if(Q70UtilidadesXML.searchDomNode(doc,Q70Constantes.PATH_CHECK_WARNING) != null){
						code = Q70UtilidadesXML.searchDomString(doc,Q70Constantes.PATH_CHECK_WARNING + Q70Constantes.PATH_CODIGO);
					} 			
			motivo = Q70UtilidadesXML.searchDomString(doc,Q70Constantes.PATH_MOTIVO);
			descripcion = Q70UtilidadesXML.searchDomString(doc,Q70Constantes.PATH_DESCRIPCION_CA);
			ErrorTraza = "(" + descripcion + " - " + motivo + ")";
			
		}catch(Q70UtilidadesExcepcion e){
			if(traza.isTraceActive())
				traza.trace(Q70Constantes.ID_COMPONENTE,Q70TraceLevel.ERROR, "Error checkeando xml devuelto por XLNets");							
			throw new Q70SeguridadException(this.getClass().getName(), "checkResult", ErrorTraza, e);
		}
		if(code.equals("E002") || code.equals("W000") || code.equals("I001")){
			if(traza.isTraceActive())
				traza.trace(Q70Constantes.ID_COMPONENTE,Q70TraceLevel.INFO, "Mensajes de sesion erronea " + ErrorTraza);				
			throw new Q70LogonException(this.getClass().getName(), "checkResult " + ErrorTraza, logonPage, null);					
		}
		if(!motivo.equals("")){	
			if(traza.isTraceActive())
				traza.trace(Q70Constantes.ID_COMPONENTE,Q70TraceLevel.INFO, "Error-informacion XLNets devuelto " + ErrorTraza);				
			throw new Q70AuthorizationException(this.getClass().getName(), "checkResult", "Funcion no autorizada "+ErrorTraza, null);
		}	
	}
	
	/**
	 * Recoge todas las funciones de autorización del usuario en una aplicación.
	 * <p>
	 * @param usuarioInf Información de Seguridad del Usuario
	 * @param aplicacion Nombre de la aplicación
	 * @return funciones Vector con las funciones de autorización del usuario en la aplicación
	 */
	public Vector getApplicationSecurityAuthorizations(Q70InformacionSeguridadUsuario usuarioInf, String aplicacion) {
		Vector funciones = new Vector();
		try {
			if (cachearFunciones) {
				if (null!=usuarioInf.getSecurityAuthorizations().get(aplicacion)) {
					funciones = (Vector)usuarioInf.getSecurityAuthorizations().get(aplicacion);
				}
				if (null!=funciones && funciones.size()>0) {
					return funciones;
				} else {
					funciones = getFuncionesAutorizacion(usuarioInf, aplicacion);
				}
			} else {
				funciones = getFuncionesAutorizacion(usuarioInf, aplicacion);
			}
		} catch(Exception e) {}
		return funciones;
	}
	
	/**
	 * Recoge todas las funciones de autorización del usuario en una aplicación.
	 * <p>
	 * @param usuarioInf Información de Seguridad del Usuario
	 * @param aplicacion Nombre de la aplicación
	 * @return funciones Vector con las funciones de autorización del usuario en la aplicación
	 * @throws Q70SeguridadException
	 * @throws Q70AuthorizationException
	 * @throws Q70LogonException
	 */
	private Vector getFuncionesAutorizacion(Q70InformacionSeguridadUsuario usuarioInf, String aplicacion) throws Q70SeguridadException, Q70AuthorizationException, Q70LogonException {
		Document xml = (Document)((N38API)usuarioInf.getToolKit()).n38ItemSeguridad(aplicacion);
		checkResult(xml);
		try {
			return Q70UtilidadesXML.searchDomVector(xml, Q70Constantes.PATH_FUNCIONES_AUTORIZACION);
		} catch(Q70UtilidadesExcepcion ue) {
			throw new Q70SeguridadException(this.getClass().getName(), "getFuncionesAutorizacion", "Error al recorrer el XML de seguridad.", ue);
		}
	}
	
	/**
	 * Invoca un método de la clase de XL-Nets <code>N38APISesion</code> recibido como argumento con los parámetros especificados.
	 * <p>
	 * @param metodo Método a invocar
	 * @param parametros Parámetros de llamada
	 * @param tipoParametros Tipo de los parámetros
	 */	
	public Document executeN38APISessionMethod(Q70XLNetsAPISesionToolkitMetodos unMetodo, Object[] parametros, Class[] tipoParametros) throws Q70SeguridadException{
		String metodo = unMetodo.toString();
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		if(traza.isTraceActive())
			traza.trace(Q70Constantes.ID_COMPONENTE,Q70TraceLevel.INFO, "Ejecutando " + metodo);								
		try {
			N38APISesion as = new N38APISesion();
			Method aMethod = as.getClass().getMethod(metodo, tipoParametros);
			Document doc = (Document)aMethod.invoke(as,parametros);
			return doc;						
		} catch (Exception e) {
			throw new Q70SeguridadException(this.getClass().getName(), "executeN38APISessionMethod", "Error ejecutando " + metodo, e);
		}
	}	
	
	/**
	 * Invoca un método de la clase de XL-Nets <code>N38API</code> recibido como argumento con los parámetros especificados.
	 * <p>
	 * @param usuarioInf Información de seguridad del usuario para obtener el toolkit N38API del usuario
	 * @param metodo Método a invocar
	 * @param parametros Parámetros de llamada
	 * @param tipoParametros Tipo de los parámetros
	 */	
	public Document executeN38APIMethod(Q70InformacionSeguridadUsuario usuarioInf, Q70XLNetsAPISesionToolkitMetodos unMetodo, Object[] parametros, Class[] tipoParametros) throws Q70SeguridadException{		
		String metodo = unMetodo.toString();
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		
		if(traza.isTraceActive())
			traza.trace(Q70Constantes.ID_COMPONENTE,Q70TraceLevel.INFO, "Ejecutando metodo");				
		try {
			N38API as = usuarioInf.getToolKit();
			Method aMethod = as.getClass().getMethod(metodo, tipoParametros);
			Document doc = (Document)aMethod.invoke(as,parametros);
			return doc;						
		} catch (Exception e) {
			throw new Q70SeguridadException(this.getClass().getName(), "executeN38APIMethod", "Error ejecutando " + metodo.toString(), e);
		}
	}
		
	/**
	 * Devuelve un objeto <code>Node</code> como resultado de aplicar una expresión <b>xpath</b> a un documento de XL-Nets.
	 * <p>
	 * @param documento Documento xml con la Información de Sesión de XL-Nets
	 * @param key xpath a aplicar
	 * @return node Objeto encontrado
	 */		
	public Node getDomNode(Document documento, String key){
		try{
			return	Q70UtilidadesXML.searchDomNode(documento, key);
		}catch(Q70UtilidadesExcepcion e){
			return null;
		} 		
	}
	
	/**
	 * Devuelve un objeto <code>NodeList</code> como resultado de aplicar una expresión <b>xpath</b> a un documento de XL-Nets.
	 * @param documento Documento xml con la Información de Sesión de XL-Nets
	 * @param key xpath a aplicar
	 * @return nodeList Objeto encontrado
	 */		
	public NodeList getDomNodelist(Document documento, String key){
		try{
			return	Q70UtilidadesXML.searchDomNodeList(documento, key);
		}catch(Q70UtilidadesExcepcion e){
			return null;
		} 					 		
	}
	
	/**
	 * Devuelve un objeto String como resultado de aplicar una expresión <b>xpath</b> a un documento de XL-Nets
	 * @param documento Documento xml con la Información de Sesión de XL-Nets
	 * @param key xpath a aplicar
	 * @return domString String encontrado.
	 */		
	public String getDomString(Document documento, String key){
		try{
			return	Q70UtilidadesXML.searchDomString(documento, key); 
		}catch(Q70UtilidadesExcepcion e){
			return null;
		} 		
	}
	
	/**
	 * Devuelve un objeto Vector como resultado de aplicar una expresión <b>xpath</b> a un documento de XL-Nets
	 * @param documento Documento xml con la informacion de sesion de XL-Nets
	 * @param key xpath a aplicar
	 * @return domVector objeto encontrado.
	 */		
	public Vector getDomVector(Document documento, String key){
		try{
			return	Q70UtilidadesXML.searchDomVector(documento, key);
		}catch(Q70UtilidadesExcepcion e){
			return null;
		} 		
	}
	
	/**
	 * Devuelve el path de la página de XL-Nets a redireccionar para hacer logon de usuario
	 * @return logonPage Path de la página de logon de usuario
	 */				
	protected String getLogonPage(){
		return logonPage;
	}
	
	/**
	 * Establece el path de la página de XL-Nets a redireccionar para hacer logon de usuario
	 * @param page Path de la página de logon de usuario
	 */				
	protected void setLogonPage(String page){
		this.logonPage = page;
	}
	
	/**
	 * Devuelve <code>true</code> si en la configuración del componente <b>Gestor de Seguridad</b> se estableció 
	 * el uso de caché para las funciones de autorización y <code>false</code> en caso contrario.
	 * @return boolean true|false según sea cacheable o no
	 */				
	protected boolean isCacheable(){
		return cachearFunciones;
	}
	
	/**
	 * Establece el valor de la propiedad que indica si se cachearán las
	 * funciones de autorización.
	 * @param cache Cadena "true"|"false" según sea cacheable o no
	 */				
	protected void setCacheable(String cache){
		this.cachearFunciones = new Boolean(cache).booleanValue();
	}
	
	/**
	 * Devuelve la instancia del gestor de seguridad. En caso de que no exista la crea.
	 * @return Instancia del gestor de seguridad
	 */
	public static Q70GestorSeguridad getSingleton() {
		if (instancia == null) {
			instancia = new Q70GestorSeguridad();
		}
		return instancia;
	}

	/**
	 * @see es.ejie.frmk.control.Arrancable#afterCreate(java.lang.String)
	 * @param xml  fichero de configuracion 
	 * @throws Q70FrameworkException
	 */
	public void afterCreate(String xml) throws Q70FrameworkException{
		try {
			xmlFile = xml;
			Q70Configurador conf = new Q70Configurador(xml);
			conf.lanzarConfigurador();
		} catch (Exception e) {
			Q70TrazaInterface traza = Q70Factoria.getTraza();
			if (traza.isTraceActive()){
				traza.trace(Q70Constantes.ID_COMPONENTE, Q70TraceLevel.ERROR, "Se ha producido un error en el método afterCreate de la clase Q70GestorSeguridad");
			}
			throw new Q70FrameworkException(Q70Constantes.ID_COMPONENTE,this.getClass().toString(),"afterCreate","Se ha producido un error en el método afterCreate.",e);
		}		
	}
	
	public void beforeDestroy(){
	}
	
	public void reConfigure() throws Q70FrameworkException{
		try {
			afterCreate(xmlFile);
		} catch (Exception e) {
			Q70TrazaInterface traza = Q70Factoria.getTraza();
			if (traza.isTraceActive()){
				traza.trace(Q70Constantes.ID_COMPONENTE, Q70TraceLevel.ERROR, "Se ha producido un error en el método reConfigure de la clase Q70GestorSeguridad");
			}
			throw new Q70FrameworkException(Q70Constantes.ID_COMPONENTE,this.getClass().toString(),"reConfigure","Se ha producido un error en el método reConfigure.",e);
		}
	}
	
	/**
	 * @see es.ejie.frmk.infraestructura.seguridad.Q70GestorSeguridadInterface#getSessionId(es.ejie.frmk.infraestructura.seguridad.Q70InformacionSeguridadInterface)
	 */
	public String getSessionId(Q70InformacionSeguridadInterface sesionInf) throws Q70SeguridadException {
		try{
			return (String) ((Vector) getSessionSecurityInf(sesionInf,Q70Constantes.USUARIO)).get(0);
		}catch(Throwable e){
			return null;
		} 
	}
	
	/**
	 * @see es.ejie.frmk.infraestructura.seguridad.Q70GestorSeguridadInterface#getSessionOrganization(es.ejie.frmk.infraestructura.seguridad.Q70InformacionSeguridadInterface)
	 */
	public String getSessionOrganization(Q70InformacionSeguridadInterface sesionInf) throws Q70SeguridadException {
		try{
			return (String) ((Vector)getSessionSecurityInf(sesionInf,Q70Constantes.DEPARTAMENTO)).get(0);
		}catch(Throwable e){
			return null;
		}
	}
	
	/**
	 * @see es.ejie.frmk.infraestructura.seguridad.Q70GestorSeguridadInterface#getSessionEntity(es.ejie.frmk.infraestructura.seguridad.Q70InformacionSeguridadInterface)
	 */
	public String getSessionEntity(Q70InformacionSeguridadInterface sesionInf) throws Q70SeguridadException {
		try{
			return (String) ((Vector)getSessionSecurityInf(sesionInf,Q70Constantes.ENTIDAD)).get(0);
		}catch(Throwable e){
			return null;
		}
	}
	
	/**
	 * @param request
	 * @return Document
	 * @throws Q70FrameworkException
	 */
	public Document getSecurityUserDocument (HttpServletRequest request) throws Q70FrameworkException  {
		Q70TrazaInterface traza = Q70Factoria.getTraza();
		Document document = null;
		
		// Recuperamos el contexto
		Q70ContextoEJIE contexto = (Q70ContextoEJIE)request.getSession().getAttribute(es.ejie.frmk.presentacion.base.Q70Constantes.CONTEXT);
		if (null == contexto) {
			if (traza.isTraceActive()) {
				traza.trace(Q70Constantes.ID_COMPONENTE, Q70TraceLevel.ERROR, "ERROR para utilizar este componente debe entrar antes por un paso de operación (.do).");
			}					
			throw new Q70SeguridadException (this.getClass().getName(), "getSecurityUserDocument", "ERROR para utilizar este componente debe entrar antes por un paso de operación (.do).", null);
		} 
		Q70InformacionSeguridadUsuario informacionSeguridadUsuario = null;
		try {
			// Recuperamos la información seguridad usuario del contexto
			informacionSeguridadUsuario = (Q70InformacionSeguridadUsuario)contexto.get(es.ejie.frmk.infraestructura.seguridad.Q70Constantes.SEGURIDAD_USUARIO);
			// Retornamos el doccumento
			document = informacionSeguridadUsuario.getDocumentSesion();			
		} catch (Exception e) {
			if (traza.isTraceActive()) {
				traza.trace(Q70Constantes.ID_COMPONENTE, Q70TraceLevel.ERROR, "Necesita loguearse para recuperar el XML de seguridad de usuario.");
			}					
			throw new Q70LogonException(this.getClass().getName(), "getSecurityUserDocument ", logonPage, e);
		}
		// Retornamos el doccumento
		return document;
		
	}
	
	/**
	 * @param request
	 * @return Document
	 * @throws Q70FrameworkException
	 */
	public Document getSecurityApplicationDocument (HttpServletRequest request) throws Q70FrameworkException {
		// Recupero el nombre de aplicación
		String aplicacion = (String)request.getSession().getServletContext().getInitParameter(Q70GestorArranqueConfiguracionServidor.NOMBRE_APLICACION);
		// Creamos la informacionSeguridadAplicacion
		Q70InformacionSeguridadInterface informacionSeguridadAplicacion = Q70GestorSeguridad.getSingleton().createSecurityApplicationInfo(aplicacion);
		// Retornamos el doccumento
		return ((Q70InformacionSeguridadAplicacion)informacionSeguridadAplicacion).getSesion();
	}
}
