LDAP Compensating Transactions Explained

Spring LDAP manages compensating transactions by making record of the state in the LDAP tree before each modifying operation (bind, unbind, rebind, modifyAttributes, and rename).

This enables the system to perform compensating operations should the transaction need to be rolled back. In many cases the compensating operation is pretty straightforward. E.g. the compensating rollback operation for a bind operation will quite obviously be to unbind the entry. Other operations however require a different, more complicated approach because of some particular characteristics of LDAP databases. Specifically, it is not always possible to get the values of all Attributes of an entry, making the above strategy insufficient for e.g. an unbind operation.

This is why each modifying operation performed within a Spring LDAP managed transaction is internally split up in four distinct operations - a recording operation, a preparation operation, a commit operation, and a rollback operation. The specifics for each LDAP operation is described in the table below:

Table 6.1. 

LDAP OperationRecordingPreparationCommitRollback
bindMake record of the DN of the entry to bind.Bind the entry.No operation.Unbind the entry using the recorded DN.
renameMake record of the original and target DN.Rename the entry.No operation.Rename the entry back to its original DN.
unbindMake record of the original DN and calculate a temporary DN.Rename the entry to the temporary location.Unbind the temporary entry.Rename the entry from the temporary location back to its original DN.
rebindMake record of the original DN and the new Attributes, and calculate a temporary DN.Rename the entry to a temporary location.Bind the new Attributes at the original DN, and unbind the original entry from its temporary location.Rename the entry from the temporary location back to its original DN.
modifyAttributesMake record of the DN of the entry to modify and calculate compensating ModificationItems for the modifications to be done.Perform the modifyAttributes operation.No operation.Perform a modifyAttributes operation using the calculated compensating ModificationItems.

A more detailed description of the internal workings of the Spring LDAP transaction support is available in the javadocs.

Renaming Strategies

As described in the table above, the transaction management of some operations require the original entry affected by the operation to be temporarily renamed before the actual modification can be made in the commit. The manner in which the temporary DN of the entry is calculated is managed by a TempEntryRenamingStrategy supplied to the ContextSourceTransactionManager. Two implementations are supplied with Spring LDAP, but if specific behaviour is required a custom implementation can easily be implemented by the user. The provided TempEntryRenamingStrategy implementations are:
  • DefaultTempEntryRenamingStrategy (the default). Adds a suffix to the least significant part of the entry DN. E.g. for the DN cn=john doe, ou=users, this strategy would return the temporary DN cn=john doe_temp, ou=users. The suffix is configurable using the tempSuffix property

  • DifferentSubtreeTempEntryRenamingStrategy. Takes the least significant part of the DN and appends a subtree DN to this. This makes all temporary entries be placed at a specific location in the LDAP tree. The temporary subtree DN is configured using the subtreeNode property. E.g., if subtreeNode is ou=tempEntries and the original DN of the entry is cn=john doe, ou=users, the temporary DN will be cn=john doe, ou=tempEntries. Note that the configured subtree node needs to be present in the LDAP tree.

Note

There are some situations where the DefaultTempEntryRenamingStrategy will not work. E.g. if your are planning to do recursive deletes you'll need to use DifferentSubtreeTempEntryRenamingStrategy. This is because the recursive delete operation actually consists of a depth-first delete of each node in the sub tree individually. Since it is not allowed to rename an entry that has any children, and DefaultTempEntryRenamingStrategy would leave each node in the same subtree (with a different name) in stead of actually removing it, this operation would fail. When in doubt, use DifferentSubtreeTempEntryRenamingStrategy.