org.springframework.ldap.transaction.compensating.manager

## Class ContextSourceTransactionManager

- java.lang.Object
- - org.springframework.transaction.support.AbstractPlatformTransactionManager
  - - org.springframework.ldap.transaction.compensating.manager.ContextSourceTransactionManager

- All Implemented Interfaces:
    Serializable, InitializingBean, PlatformTransactionManager

      public class ContextSourceTransactionManager
      extends AbstractPlatformTransactionManager
      implements InitializingBean

  TransactionManager for managing LDAP transactions. Since transactions are not supported in the LDAP protocol, this class and its collaborators aim to provide compensating transactions instead. Should a transaction need to be rolled back, this TransactionManager will try to restore the original state using information recorded prior to each operation. The operation where the original state is restored is called a compensating operation.

  NOTE: The transactions provided by this TransactionManager are all client side and are by no means 'real' transactions, in the sense that we know them in the ordinary database world, e.g.:

  - Should the transaction failure be caused by a network failure, there is no way whatsoever that this TransactionManager can restore the database state. In this case, all possibilities for rollback will be utterly lost.
  - Transaction isolation is not provided, i.e. entries participating in a transaction for one client may very well participate in another transaction for another client at the same time. Should one of these transactions be rolled back, the outcome of this is undetermined, and may in the worst case result in total failure.

  While the points above should be noted and considered, the compensating transaction approach will be perfectly sufficient for all but the most unfortunate of circumstances. Considering that there currently is a total absence of server-side transaction support in the LDAP world, being able to mark operations as transactional in the same way as for relational database operations is surely a step forward.

  An LDAP transaction is tied to a `ContextSource`, to be supplied to the `setContextSource(ContextSource)` method. While the actual ContextSource used by the target LdapTemplate instance needs to be of the type `TransactionAwareContextSourceProxy`, the ContextSource supplied to this class should be the actual target ContextSource.

  Using this TransactionManager along with `TransactionAwareContextSourceProxy`, all modifying operations (bind, unbind, rebind, rename, modifyAttributes) in a transaction will be intercepted. Each modification has its corresponding `CompensatingTransactionOperationRecorder`, which collects the information necessary to perform a rollback and produces a `CompensatingTransactionOperationExecutor` which is then used to execute the actual operation and is later called for performing the commit or rollback.

  For several of the operations, performing a rollback is pretty straightforward. For example, in order to roll back a rename operation, it will only be required to rename the entry back to its original position. For other operations, however, it's a bit more complicated. An unbind operation is not possible to roll back by simply binding the entry back with the attributes retrieved from the original entry. It might not be possible to get all the information from the original entry. Consequently, the `UnbindOperationExecutor` will move the original entry to a temporary location in its performOperation() method. The commit() method will know that everything went well, so it will be OK to unbind the entry. The rollback operation will be to rename the entry back to its original location. The same behaviour is used for rebind() operations. The operation of calculating a temporary location for an entry is delegated to a `TempEntryRenamingStrategy` (default `DefaultTempEntryRenamingStrategy`), specified in `setRenamingStrategy(TempEntryRenamingStrategy)`.

  The actual work of this Transaction Manager is delegated to a `ContextSourceTransactionManagerDelegate`. This is because the exact same logic needs to be used if we want to wrap a JDBC and LDAP transaction in the same logical transaction.

  Since:
    1.2
  Author:
    Mattias Hellborg Arthursson
  See Also:
    `ContextSourceAndDataSourceTransactionManager`, `ContextSourceTransactionManagerDelegate`, `DefaultCompensatingTransactionOperationManager`, `TempEntryRenamingStrategy`, `TransactionAwareContextSourceProxy`, Serialized Form

- - ### Nested Class Summary

    - ### Nested classes/interfaces inherited from class org.springframework.transaction.support.AbstractPlatformTransactionManager

      `AbstractPlatformTransactionManager.SuspendedResourcesHolder`

  - ### Field Summary

    - ### Fields inherited from class org.springframework.transaction.support.AbstractPlatformTransactionManager

      `logger, SYNCHRONIZATION_ALWAYS, SYNCHRONIZATION_NEVER, SYNCHRONIZATION_ON_ACTUAL_TRANSACTION`

  - ### Constructor Summary

    Constructors
    Constructor and Description
    `ContextSourceTransactionManager()`

  - ### Method Summary

    All Methods Instance Methods Concrete Methods
    Modifier and Type | Method and Description
    --- | ---
    `void` | `afterPropertiesSet()`
    `protected void` | `doBegin(Object transaction, TransactionDefinition definition)`
    `protected void` | `doCleanupAfterCompletion(Object transaction)`
    `protected void` | `doCommit(DefaultTransactionStatus status)`
    `protected Object` | `doGetTransaction()`
    `protected void` | `doRollback(DefaultTransactionStatus status)`
    `ContextSource` | `getContextSource()` Get the ContextSource.
    `protected boolean` | `isExistingTransaction(Object transaction)`
    `void` | `setContextSource(ContextSource contextSource)` Set the ContextSource.
    `void` | `setRenamingStrategy(TempEntryRenamingStrategy renamingStrategy)` Set the `TempEntryRenamingStrategy`.

    - ### Methods inherited from class org.springframework.transaction.support.AbstractPlatformTransactionManager

      `commit, determineTimeout, doResume, doSetRollbackOnly, doSuspend, getDefaultTimeout, getTransaction, getTransactionSynchronization, invokeAfterCompletion, isFailEarlyOnGlobalRollbackOnly, isGlobalRollbackOnParticipationFailure, isNestedTransactionAllowed, isRollbackOnCommitFailure, isValidateExistingTransaction, newTransactionStatus, prepareForCommit, prepareSynchronization, prepareTransactionStatus, registerAfterCompletionWithExistingTransaction, resume, rollback, setDefaultTimeout, setFailEarlyOnGlobalRollbackOnly, setGlobalRollbackOnParticipationFailure, setNestedTransactionAllowed, setRollbackOnCommitFailure, setTransactionSynchronization, setTransactionSynchronizationName, setValidateExistingTransaction, shouldCommitOnGlobalRollbackOnly, suspend, triggerBeforeCommit, triggerBeforeCompletion, useSavepointForNestedTransaction`

    - ### Methods inherited from class java.lang.Object

      `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- - ### Constructor Detail

    - #### ContextSourceTransactionManager

          public ContextSourceTransactionManager()

  - ### Method Detail

    - #### doBegin

          protected void doBegin(Object transaction,
                                 TransactionDefinition definition)

      Specified by:
        `doBegin` in class `AbstractPlatformTransactionManager`

    - #### doCleanupAfterCompletion

          protected void doCleanupAfterCompletion(Object transaction)

      Overrides:
        `doCleanupAfterCompletion` in class `AbstractPlatformTransactionManager`

    - #### doCommit

          protected void doCommit(DefaultTransactionStatus status)

      Specified by:
        `doCommit` in class `AbstractPlatformTransactionManager`

    - #### doGetTransaction

          protected Object doGetTransaction()

      Specified by:
        `doGetTransaction` in class `AbstractPlatformTransactionManager`

    - #### doRollback

          protected void doRollback(DefaultTransactionStatus status)

      Specified by:
        `doRollback` in class `AbstractPlatformTransactionManager`

    - #### getContextSource

          public ContextSource getContextSource()

      Get the ContextSource.
      Returns:
        the contextSource.
      See Also:
        `ContextSourceTransactionManagerDelegate.getContextSource()`

    - #### setContextSource

          public void setContextSource(ContextSource contextSource)

      Set the ContextSource.
      Parameters:
        `contextSource` - the ContextSource.
      See Also:
        `ContextSourceTransactionManagerDelegate.setContextSource(ContextSource)`

    - #### setRenamingStrategy

          public void setRenamingStrategy(TempEntryRenamingStrategy renamingStrategy)

      Set the `TempEntryRenamingStrategy`.
      Parameters:
        `renamingStrategy` - the Renaming Strategy.
      See Also:
        `ContextSourceTransactionManagerDelegate.setRenamingStrategy(TempEntryRenamingStrategy)`

    - #### afterPropertiesSet

          public void afterPropertiesSet()
                                  throws Exception

      Specified by:
        `afterPropertiesSet` in interface `InitializingBean`
      Throws:
        `Exception`

    - #### isExistingTransaction

          protected boolean isExistingTransaction(Object transaction)
                                           throws TransactionException

      Overrides:
        `isExistingTransaction` in class `AbstractPlatformTransactionManager`
      Throws:
        `TransactionException`