Spring Ldap: gestión de transacciones y configuración de un pool de conexiones.
0. Índice de contenidos.
- 1. Introducción.
- 2. Entorno.
- 3. Transacciones con el soporte de Spring ldap.
- 4. Configuración de un pool de conexiones contra ldap.
- 5. Referencias.
- 6. Conclusiones.
1. Introducción
Este tutorial continúa con los primeros pasos que dimos
implementando operaciones básicas con el soporte de plantillas de Spring ldap, ahora con un mayor grado de profundidad.
Nuestro objetivo ahora es claro, ponernos en producción, y para ello necesitaremos disponer del soporte que nos
proporcionaría cualquier recurso de fuente de datos si trabajásemos con JDBC, a saber:
- Disponer de una gestión de transacciones para que que el contenido de nuestro directorio se mantenga consistente
frente a errores en la ejecución de varias operaciones, cuando unas dependan de otras, de tal forma que podamos disponer
de atomicidad. - Poder configurar un pool que nos permita controlar cuántas conexiones físicas se pueden abrir y
permita reutilizar los recursos de una manera eficiente.
2. Entorno.
El tutorial, y el código que contiene, han sido escritos usando el siguiente entorno:
- Hardware: Portátil MacBook Pro 15′ (2.3 GHz Intel Core i7, 16GB DDR3).
- Sistema Operativo: Mac OS Mavericks 10.9.2
- Eclipse Kepler + m2e plugin
- Spring Ldap 2.0.1
3. Transacciones con el soporte de Spring ldap.
El protocolo ldap no define una gestión de transacciones en las operaciones, de hecho no todos los servidores ldap
proporcionan dicho soporte.
Conscientes de ello, el proyecto Spring ldap proporciona un sistema de compensación en de las siguientes operaciones,
aunque la implementación de ldap con la que trabajemos no proporcione soporte para gestionar las transacciones
del lado del servidor.
Operación | Prepara | Commit | Rollback |
---|---|---|---|
bind | Almacena el DN del registro | No realiza operaciones | Ejecuta un unbind usando el DN almacenado |
rename | Almacena el DN del registro original y del nuevo | No realiza operaciones | Renombra la entrada para volver a la entrada original |
unbind | Almacena el DN del registro original y calcula un DN temporal para renombrar el registro al DN temporal | Ejecuta un unbind del registro temporal | Renombra la entrada temporal para devolverla a la original |
rebind | Almacena el DN del registro original, los nuevos atributos y calcula un DN temporal. Renombra la entrada a una ubicación temporal. | Almacena los atributos y el DN original y elimina el original de la ubicación temporal. | Renombra la entrada temporal para devolverla a la original |
modifyAttributes | Almacena el DN de la entrada para modificar, ejecuta las modificaciones y calcula las operaciones de compensación de los atributos a modificar. | No realiza operaciones | Ejecuta una operación de modificación de atributos con los calculados para la compensación. |
Frente a cada una de estas operaciones la plantilla prepara el sistema de compensación y en el commit o el rollback ejecuta, o no, una acción.
Para configurar la gestión de transacciones, disponiendo del soporte de contexto de inyección de dependencias, añadiríamos la siguiente configuración:
<context:component-scan base-package="com.autentia.courses.ldap" /> <beans> <bean id="contextSourceTarget" class="org.springframework.ldap.core.support.LdapContextSource"> <property name="url" value="ldap://localhost:11389" /> <property name="userDn" value="cn=Directory Manager" /> <property name="password" value="opendj" /> <property name="base" value=""/> </bean> <bean id="contextSource" class="org.springframework.ldap.transaction.compensating.manager.TransactionAwareContextSourceProxy"> <constructor-arg ref="contextSourceTarget" /> </bean> <bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate"> <constructor-arg ref="contextSource" /> </bean> <bean id="transactionManager" class="org.springframework.ldap.transaction.compensating.manager.ContextSourceTransactionManager"> <property name="contextSource" ref="contextSource" /> </bean> <tx:annotation-driven transaction-manager="transactionManager" /> </beans>
Con ello, ya podemos anotar nuestras clases de servicio con @Transacional y trabajar con el mismo comportamiento que
si trabajásemos con JDBC o JPA y el soporte de Spring, aún sin que nuestro servidor Ldap soporte transacciones.
4. Configuración de un pool de conexiones contra ldap.
Un pool de conexiones es una técnica donde las conexiones son reutilizadas en vez de crear una nueva cada vez se
solicita una conexión. Sin un pool, se crea una conexión por petición y se libera cuando deja de utilizarse. Crear
una conexión implica el uso intensivo de recursos y puede tener efectos a nivel de rendimiento. Con un pool, las
conexiones se almacenan en él después de ser creadas y se reciclan para siguientes peticiones.
Las peticiones en un pool pueden tener tres estados:
- en uso: está abierta y se está usando
- idle: está abierta y lista para reutilizarse,
- cerrada: no está disponible par su uso.
JNDI proporciona un pool de conexiones por defecto que permite ser activado de una manera muy simple, si bien, no hay
control sobre las propiedades del pool, como por ejemplo, el número máximo de conexiones abiertas.
Para configurar el pool de conexiones de ldap basta con añadir a nuestra cadena de configuraciones el siguiente bean de tipo org.springframework.ldap.pool.factory.PoolingContextSource
:
<bean id="contextSourceTarget" class="org.springframework.ldap.core.support.LdapContextSource"> <property name="url" value="ldap://localhost:389" /> <property name="base" value="dc=example,dc=com" /> <property name="userDn" value="cn=Manager" /> <property name="password" value="secret" /> <property name="pooled" value="false"/> </bean> <bean id="contextSource" class="org.springframework.ldap.pool.factory.PoolingContextSource"> <property name="contextSource" ref="contextSourceTarget" /> </bean> <bean id="ldapTemplate" class="org.springframework.ldap.core.LdapTemplate"> <constructor-arg ref="contextSource" /> </bean>
Para que el pool funcione debemos mantener una dependencia con la librería commons-pool, de modo tal que dicho jar
debe existir en nuestro classpath.
Se pueden configurar las siguientes propiedades del pool:
Propiedad | Descripcíon | Valor por defecto |
---|---|---|
testOnBorrow | Esta propiedad indica que las instancias de DirContext deben ser validadas antes de usarse por el pool. Si una falla se desecha y se abre una nueva conexión para ser usada. Esta comprobación añade un pequeño retardo el responder a la petición de conexión. | False |
testOnReturn | Esta propiedad indica que las instancias de DirContext debe ser validadas antes de deolverlas del pool. | False |
testWhileIdle | Esta propiedad indica que las instancias de DirContext en espera en el pool deben ser validadas con una frecuencia especificada. Los objetos que no pasen la validación serán elimiados del pool. | False |
timeBetweenEvictionRunsMillis | Esta propiedad indica el tiempo en milisegundos de espera mientras se ejecutan las pruebas sobre las conexiones en espera. Un valor negativo indica que las pruebas no se ejecutarán nunca. | -1 |
whenExhaustedAction | Especifica la acción a realizar cuando el pool está lleno. Las posibles acciones son WHEN_EXHAUSTED_FAIL (0), WHEN_EXHAUSTED_BLOCK (1), y WHEN_ EXHAUSTED_GROW (2). | 1 |
maxTotal | El número máximo de conexiones activas que el pool puede mantener. Un número negativo indica que no hay límite. | -1 |
maxIdle | El número máximo de conexiones en espera de cada tipo (read, read-write) que pueden permanecer vivos en el pool. | 8 |
maxWait | El número máximo de milisegundos que el pool esperará para devolver una conexión antes de lanzar una excepción. Un número negativo indica una espera infinita. | -1 |
5. Referencias.
- http://projects.spring.io/spring-ldap/
- https://adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=springLdapTemplate
- https://adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=apacheDSEmbeddedLDAPServer
6. Conclusiones.
Ya estamos listos para un entorno de producción!.
Un saludo.
Jose