Los Web Services fueron pensados en un inicio para que no mantuvieran estados de las sesiones. Es lógico que si lo que estamos ofreciendo es un servicio, no sea necesario que se mantenga información de las consultas anteriores. Si por ejemplo tenemos un WS que sirve información de la bolsa, en cada consulta se mandará la información que se ha solicitado, pero no necesitamos saber cosas acerca de las consultas anteriores. El servicio es una consulta, y la respuesta es independiente de las anteriores.

Pero como siempre, las cosas evolucionan, y siempre hay gente que necesita darle una vuelta de tuerca a todo. Así que quizás estéis creando un WS y necesitáis que se guarde el estado de cada petición. De hecho a nosotros nos pasó. Teníamos que montar una capa intermedia para que conectara y consultara con un gestor documental, pero además una de las necesidades que había es que se mantuviese abierta la conexión durante un tiempo determinado. Son estas cosas que te vienen dadas, y que no otra que buscarte la vida para ver como lo implementas.

En este tutorial no vamos a hacer un ejemplo, pero os vamos a decir paso a paso qué es lo que tenéis que hacer para conseguir mantener las sesiones en Axis2. Está probado con la versión 1.2 de Axis2. No sabemos si algo habrá dejado de funcionar en versiones posteriores.

Lo primero que tenéis que tener en cuenta es que hay que tocar cosas en el cliente para que el WS mantenga la sesión. Sí, el hecho de que la sesión se mantenga en el servidor debería ser independiente del cliente, pero en Axis2 no es así. Cuando el WS recibe un mensaje SOAP de un cliente, en la respuesta incluirá una nueva cabecera SOAP (serviceGroupId) con un identificador único. Lo que hay que hacer en la parte cliente es que en las sucesivos mensajes que envíe, incluya dicha cabecera con el mismo identificador para  que el WS sepa que ese mensaje viene de un cliente que ya tiene sesión. Pero mejor vayamos poco a poco:

Tipos de sesiones en Axis2

Cuando definimos que un servicio mantiene sesiones, tenemos que especificar el ámbito de las mismas. Podemos tener las siguientes opciones:

  • Petición (Request) – Es el ámbito por defecto que tiene Axis2, y la sesión dura lo que tarda en servirse la petición, vamos que no tenéis sesión :)
  • Sesión SOAP (SOAPSession) – Si configuramos el servicio para que mantenga sesiones con este ámbito, podremos mantener sesiones en el servidor siempre y cuando el cliente envíe la cabecera SOAP serviceGroupId que el WS le envió con la respuesta al primer mensaje. De esta forma el WS sabe que un nuevo mensaje pertenece a una sesión anterior.
  • Aplicación (Application) – Una sesión de este ámbito está compartida por toda la aplicación y no es única por cliente. Si modificamos datos en la sesión de la aplicación, afectará a todos los mensajes que lleguen, pues todos los clientes comparten la sesión de aplicación.
  • Transporte (Transport) – En este caso, la sesión es única para cada cliente, pero en lugar de ser controlada por Axis2 mediante la cabecera SOAP serviceGroupId, es el protocolo de transporte el encargado de controlar la sesión. Por ejemplo, en HTTP se utilizarán las cookies para mantener la sesión. En cualquier caso, desde el cliente habrá que copiar las cookies para que en las llamadas posteriores el WS sepa a qué sesión pertenecen.

SOAPSession

Para que el ámbito de sesión de nuestro WS sea éste, tenemos que incluir el atributo:

scope="soapsession"

en el tag:

<service>

del fichero services.xml. Ejemplo:

<service name="elNombreDeTuWS" scope="soapsession">

E incluir dentro del tag <service> un nuevo tag:

<module ref=”addressing”/>

Dentro de una clase, para acceder a los datos de la sesión habría que hacer lo siguiente:

// Obtenemos el contexto del servicio
ServiceContext serviceContext = MessageContext.getCurrentMessageContext().getServiceContext();

// Así guardamos un objeto en la sesión
serviceContext.setProperty("nombre", obj);

// Así lo recuperamos
MiObjeto obj = (MiObjeto)serviceContext.getProperty("nombre");

Application

Para que el ámbito de sesión de nuestro WS sea éste, tenemos que incluir el atributo: scope="application"

en el tag:

<service>

del fichero services.xml. Ejemplo:

<service name="elNombreDeTuWS" scope="application">

Dentro de la clase que implementa el WS para acceder a los datos de la sesión de aplicación habría que hacer lo siguiente:

// Obtenemos el contexto del servicio
ServiceContext serviceContext = MessageContext.getCurrentMessageContext().getServiceContext();

// Obtenemos el contexto de la configuración
ConfigurationContext configurationContext = serviceContext.getConfigurationContext();

// Así recuperamos un objeto de la sesión
MiObjeto obj = (MiObjeto)configurationContext.getProperty("nombre");

// Y así lo guardamos
configurationContext.setProperty("nombre", obj);

Transport

Para que el ámbito de sesión de nuestro WS sea éste, tenemos que incluir el atributo:

scope="transportsession"

en el tag:

<service>

del fichero services.xml. Ejemplo:

<service name="elNombreDeTuWS" scope="transportsession">

E incluir dentro del tag <service> un nuevo tag:

<module ref="addressing"/>

Si estáis utilizando alguna "nightly version" de Axis2 o alguna versión posterior a la 1.2, quizás tengáis que incluir también las siguientes líneas en el fichero axis2.xml (dentro del directorio donde tengáis instalado Axis2):

<parameter name="manageTransportSession" locked="false">true</parameter>

Dentro de la clase que implementa el WS para acceder a los datos de la sesión habría que hacer lo siguiente:

// Obtenemos el contexto del servicio
ServiceContext serviceContext = MessageContext.getCurrentMessageContext().getServiceContext();

// Así guardamos un objeto en la sesión
serviceContext.setProperty("nombre", obj);

// Así lo recuperamos
MiObjeto obj = (MiObjeto)serviceContext.getProperty("nombre");

Configuración del cliente

Como hemos venido diciendo, tanto si estamos utilizando sesiones en el ámbito de la sesión SOAP, como en el ámbito del transporte, tendremos que hacer cosas en el cliente para que se mantenga la sesión en el servidor. El WS nos devolverá en la cabecera SOAP (SOAPSession) o en las cookies (Transport) el identificador de nuestra sesión, pero el cliente tiene que devolvérselo en las llamadas posteriores. Podéis programarlo para que copie la cabecera o las HTTP cookies y las reenvíe después, pero Axis2 ofrece una solución más sencilla (aunque un poco engorrosa). Tenemos que activar el módulo de addressing en el cliente, y para ello tenemos que crear un "ConfigurationContext". Vamos a ver el código para que se vea más claro:

// Creamos el ConfigurationContext a partir de los ficheros de configuración
ConfigurationContext configurationContext = ConfigurationContextFactory.createConfigurationContextFromFileSystem("C:\\Axis2-SNAPSHOT\\repository", "C:\\Axis2-SNAPSHOT\\conf\\axis2.xml");

// Donde pone "URL del endpoint" iría la URL real de nuestro WS
MiClaseStub miclaseStub = new EjemploStub(configurationContext, "URL del endpoint");

// Activamos el módulo de addressing
miclaseStub._getServiceClient().engageModule("addressing");

// Activamos el manejo de sesiones
miclaseStub._getServiceClient().getOptions().setManageSession(true);

Como estamos cargando la configuración desde fichero, hay que copiar los ficheros de configuración de Axis2 que necesitamos en el cliente. Hemos creado una carpeta a la que hemos llamado "Axis2-SNAPSHOT" y dentro tenemos lo siguiente:

  • conf
    • axis2.xml
  • repository
    • modules
      • addressing-1.2
      • modules.list
      • soapmonitor-1.2

Al utilizar el método "createConfigurationContextFromFileSystem" del "ConfigurationContextFactory", le indicamos la ruta en la que están los ficheros de configuración y los módulos que necesita el cliente para gestionar las sesiones. Estos ficheros los copiamos de la instalación de Axis2. Con esto el cliente ya reenviará el identificador de sesión en la cabecera SOAP al WS en las llamadas posteriores.

La verdad es que no es una tarea sencilla el configurar las sesiones con Axis2, sobre todo por la parte del cliente, pero esperemos que con este tutorial os resulte un poco más sencillo. Saludos y hasta el próximo tutorial.