Transaction recording and rollback support for bind and rebind.
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
package org.springframework.ldap.support.transaction;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.DirContext;
|
||||
|
||||
import org.springframework.ldap.ContextSource;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.TransactionException;
|
||||
import org.springframework.transaction.support.AbstractPlatformTransactionManager;
|
||||
import org.springframework.transaction.support.DefaultTransactionStatus;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
|
||||
/**
|
||||
* TransactionManager for managing LDAP transactions. Since transactions are not
|
||||
* supported in the LDAP protocol, this class and its collaborators aims to
|
||||
* provide compensating transactions instead. TODO: improve javadoc.
|
||||
*
|
||||
* @author Mattias Arthursson
|
||||
*/
|
||||
public class ContextSourceTransactionManager extends
|
||||
AbstractPlatformTransactionManager {
|
||||
|
||||
private ContextSource contextSource;
|
||||
|
||||
/**
|
||||
* Set the ContextSource to work on. The supplied ContextSource must be of the type abstract
|
||||
*
|
||||
* @param contextSource
|
||||
* the ContextSource to work on.
|
||||
*/
|
||||
public void setContextSource(ContextSource contextSource) {
|
||||
this.contextSource = contextSource;
|
||||
}
|
||||
|
||||
public ContextSource getContextSource() {
|
||||
return contextSource;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#doGetTransaction()
|
||||
*/
|
||||
protected Object doGetTransaction() throws TransactionException {
|
||||
DirContextHolder contextHolder = (DirContextHolder) TransactionSynchronizationManager
|
||||
.getResource(this.contextSource);
|
||||
ContextSourceTransactionObject txObject = new ContextSourceTransactionObject(
|
||||
contextHolder);
|
||||
return txObject;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#doBegin(java.lang.Object,
|
||||
* org.springframework.transaction.TransactionDefinition)
|
||||
*/
|
||||
protected void doBegin(Object transaction, TransactionDefinition definition)
|
||||
throws TransactionException {
|
||||
ContextSourceTransactionObject txObject = (ContextSourceTransactionObject) transaction;
|
||||
|
||||
if (txObject.getContextHolder() == null) {
|
||||
DirContext newCtx = getContextSource().getReadOnlyContext();
|
||||
DirContextHolder contextHolder = new DirContextHolder(newCtx);
|
||||
|
||||
txObject.setContextHolder(contextHolder);
|
||||
TransactionSynchronizationManager.bindResource(getContextSource(),
|
||||
contextHolder);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#doCommit(org.springframework.transaction.support.DefaultTransactionStatus)
|
||||
*/
|
||||
protected void doCommit(DefaultTransactionStatus status)
|
||||
throws TransactionException {
|
||||
// Nothing much to do here.
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#doRollback(org.springframework.transaction.support.DefaultTransactionStatus)
|
||||
*/
|
||||
protected void doRollback(DefaultTransactionStatus status)
|
||||
throws TransactionException {
|
||||
// Perform compensating transaction cleanup using information stored in
|
||||
// ContextHolder.
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#doCleanupAfterCompletion(java.lang.Object)
|
||||
*/
|
||||
protected void doCleanupAfterCompletion(Object transaction) {
|
||||
ContextSourceTransactionObject txObject = (ContextSourceTransactionObject) transaction;
|
||||
TransactionSynchronizationManager.unbindResource(contextSource);
|
||||
DirContext ctx = txObject.getContextHolder().getCtx();
|
||||
|
||||
try {
|
||||
ctx.close();
|
||||
} catch (NamingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
txObject.getContextHolder().clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Transaction object for ContextSourceTransactionManager.
|
||||
*
|
||||
* @author Mattias Arthursson
|
||||
*/
|
||||
static class ContextSourceTransactionObject {
|
||||
private DirContextHolder contextHolder;
|
||||
|
||||
public ContextSourceTransactionObject(DirContextHolder contextHolder) {
|
||||
this.contextHolder = contextHolder;
|
||||
}
|
||||
|
||||
public DirContextHolder getContextHolder() {
|
||||
return contextHolder;
|
||||
}
|
||||
|
||||
public void setContextHolder(DirContextHolder contextHolder) {
|
||||
this.contextHolder = contextHolder;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.springframework.ldap.support.transaction;
|
||||
|
||||
import javax.naming.directory.DirContext;
|
||||
|
||||
import org.springframework.transaction.support.ResourceHolderSupport;
|
||||
|
||||
public class DirContextHolder extends ResourceHolderSupport {
|
||||
private DirContext ctx;
|
||||
|
||||
private CompensatingTransactionDataManager transactionDataManager;
|
||||
|
||||
public void setCtx(DirContext ctx) {
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
public DirContextHolder(DirContext ctx) {
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
public DirContext getCtx() {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
super.clear();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package org.springframework.ldap.support.transaction;
|
||||
|
||||
import javax.naming.directory.DirContext;
|
||||
|
||||
public interface DirContextProxy {
|
||||
DirContext getTargetContext();
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package org.springframework.ldap.support.transaction;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
import javax.naming.directory.DirContext;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.ldap.ContextSource;
|
||||
import org.springframework.ldap.LdapOperations;
|
||||
import org.springframework.ldap.LdapTemplate;
|
||||
|
||||
public class LdapCompensatingTransactionDataManager implements
|
||||
CompensatingTransactionDataManager {
|
||||
|
||||
private Stack rollbackOperations = new Stack();
|
||||
|
||||
private LdapOperations ldapOperations;
|
||||
|
||||
public LdapCompensatingTransactionDataManager(DirContext ctx) {
|
||||
this.ldapOperations = new LdapTemplate(new SingleContextSource(ctx));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.ldap.support.CompensatingTransactionDataManager#operationPerformed(java.lang.String,
|
||||
* java.lang.Object[])
|
||||
*/
|
||||
public void operationPerformed(String operation, Object[] params) {
|
||||
CompensatingTransactionRecordingOperation recordingOperation = getRecordingOperation(operation);
|
||||
rollbackOperations.push(recordingOperation.performOperation(params));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.ldap.support.CompensatingTransactionDataManager#rollback()
|
||||
*/
|
||||
public void rollback() {
|
||||
while (!rollbackOperations.isEmpty()) {
|
||||
CompensatingTransactionRollbackOperation rollbackOperation = (CompensatingTransactionRollbackOperation) rollbackOperations
|
||||
.pop();
|
||||
rollbackOperation.rollback();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the rollback operations. Package protected for testing purposes.
|
||||
*
|
||||
* @return the rollback operations.
|
||||
*/
|
||||
Stack getRollbackOperations() {
|
||||
return rollbackOperations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the rollback operations. Package protected - for testing purposes
|
||||
* only.
|
||||
*
|
||||
* @param rollbackOperations
|
||||
* the rollback operations.
|
||||
*/
|
||||
void setRollbackOperations(Stack rollbackOperations) {
|
||||
this.rollbackOperations = rollbackOperations;
|
||||
}
|
||||
|
||||
protected CompensatingTransactionRecordingOperation getRecordingOperation(
|
||||
String operation) {
|
||||
return null;
|
||||
}
|
||||
|
||||
static class SingleContextSource implements ContextSource {
|
||||
private DirContext ctx;
|
||||
|
||||
public SingleContextSource(DirContext ctx) {
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
public DirContext getReadOnlyContext() throws DataAccessException {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
public DirContext getReadWriteContext() throws DataAccessException {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package org.springframework.ldap.support.transaction;
|
||||
|
||||
import javax.naming.Name;
|
||||
|
||||
import org.springframework.ldap.support.DistinguishedName;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Common helper methods for Ldap operations.
|
||||
*
|
||||
* @author Mattias Arthursson
|
||||
*/
|
||||
public class LdapUtils {
|
||||
/**
|
||||
* Not to be instantiated.
|
||||
*/
|
||||
private LdapUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first parameter in the argument list as a Name.
|
||||
*
|
||||
* @param args
|
||||
* arguments supplied to a ldap operation.
|
||||
* @return a Name representation of the first argument, or the Name itself
|
||||
* if it is a name.
|
||||
*/
|
||||
public static Name getFirstArgumentAsName(Object[] args) {
|
||||
Assert.notEmpty(args);
|
||||
|
||||
if (args[0] instanceof String) {
|
||||
return new DistinguishedName((String) args[0]);
|
||||
} else if (args[0] instanceof Name) {
|
||||
return (Name) args[0];
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"First argument needs to be a Name or a String representation thereof");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.springframework.ldap.support.transaction;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
public class NullRollbackOperation implements
|
||||
CompensatingTransactionRollbackOperation {
|
||||
|
||||
private static Log log = LogFactory.getLog(NullRollbackOperation.class);
|
||||
|
||||
public void rollback() {
|
||||
log.info("Rolling back null operation");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.springframework.ldap.support.transaction;
|
||||
|
||||
import javax.naming.Name;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.ldap.LdapOperations;
|
||||
import org.springframework.ldap.support.DirContextAdapter;
|
||||
|
||||
public class RebindRecordingOperation implements
|
||||
CompensatingTransactionRecordingOperation {
|
||||
|
||||
private static Log log = LogFactory.getLog(RebindRecordingOperation.class);
|
||||
|
||||
private LdapOperations ldapOperations;
|
||||
|
||||
public RebindRecordingOperation(LdapOperations ldapOperations) {
|
||||
this.ldapOperations = ldapOperations;
|
||||
}
|
||||
|
||||
public CompensatingTransactionRollbackOperation performOperation(
|
||||
Object[] args) {
|
||||
Name dn = LdapUtils.getFirstArgumentAsName(args);
|
||||
|
||||
try {
|
||||
DirContextAdapter ctx = (DirContextAdapter) ldapOperations
|
||||
.lookup(dn);
|
||||
return new RebindRollbackOperation(ldapOperations, ctx);
|
||||
} catch (Exception e) {
|
||||
log.warn(
|
||||
"Failed to create rollback operation, dn " + dn.toString(),
|
||||
e);
|
||||
return new NullRollbackOperation();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.springframework.ldap.support.transaction;
|
||||
|
||||
import javax.naming.Name;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.ldap.LdapOperations;
|
||||
import org.springframework.ldap.support.DirContextOperations;
|
||||
|
||||
public class RebindRollbackOperation implements
|
||||
CompensatingTransactionRollbackOperation {
|
||||
|
||||
private static Log log = LogFactory.getLog(RebindRollbackOperation.class);
|
||||
|
||||
private LdapOperations ldapOperations;
|
||||
|
||||
private DirContextOperations dirContextOperations;
|
||||
|
||||
public RebindRollbackOperation(LdapOperations ldapOperations,
|
||||
DirContextOperations dirContextOperations) {
|
||||
this.ldapOperations = ldapOperations;
|
||||
this.dirContextOperations = dirContextOperations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the targegt DirContextOperations. Package private for testing
|
||||
* purposes.
|
||||
*
|
||||
* @return the DirContextOperations.
|
||||
*/
|
||||
DirContextOperations getDirContextOperations() {
|
||||
return dirContextOperations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the LdapOperations. Package private for testing purposes.
|
||||
*
|
||||
* @return the LdapOperations.
|
||||
*/
|
||||
LdapOperations getLdapOperations() {
|
||||
return ldapOperations;
|
||||
}
|
||||
|
||||
public void rollback() {
|
||||
Name dn = dirContextOperations.getDn();
|
||||
try {
|
||||
ldapOperations.rebind(dn, dirContextOperations, null);
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to rollback operation, dn: " + dn, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package org.springframework.ldap.support.transaction;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.easymock.MockControl;
|
||||
import org.springframework.ldap.LdapOperations;
|
||||
import org.springframework.ldap.support.DirContextAdapter;
|
||||
import org.springframework.ldap.support.DirContextOperations;
|
||||
import org.springframework.ldap.support.DistinguishedName;
|
||||
|
||||
public class RebindRollbackOperationTest extends TestCase {
|
||||
|
||||
private MockControl ldapOperationsControl;
|
||||
|
||||
private LdapOperations ldapOperationsMock;
|
||||
|
||||
private MockControl dirContextOperationsControl;
|
||||
|
||||
private DirContextOperations dirContextOperationsMock;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
ldapOperationsControl = MockControl.createControl(LdapOperations.class);
|
||||
ldapOperationsMock = (LdapOperations) ldapOperationsControl.getMock();
|
||||
|
||||
dirContextOperationsControl = MockControl
|
||||
.createControl(DirContextOperations.class);
|
||||
dirContextOperationsMock = (DirContextOperations) dirContextOperationsControl
|
||||
.getMock();
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
ldapOperationsControl = null;
|
||||
ldapOperationsMock = null;
|
||||
|
||||
dirContextOperationsControl = null;
|
||||
dirContextOperationsMock = null;
|
||||
}
|
||||
|
||||
protected void replay() {
|
||||
ldapOperationsControl.replay();
|
||||
dirContextOperationsControl.replay();
|
||||
}
|
||||
|
||||
protected void verify() {
|
||||
ldapOperationsControl.verify();
|
||||
dirContextOperationsControl.verify();
|
||||
}
|
||||
|
||||
public void testRollback() {
|
||||
RebindRollbackOperation tested = new RebindRollbackOperation(
|
||||
ldapOperationsMock, dirContextOperationsMock);
|
||||
|
||||
DistinguishedName expectedName = new DistinguishedName("cn=john doe");
|
||||
dirContextOperationsControl.expectAndReturn(dirContextOperationsMock
|
||||
.getDn(), expectedName);
|
||||
ldapOperationsMock.rebind(expectedName, dirContextOperationsMock, null);
|
||||
|
||||
replay();
|
||||
// perform test
|
||||
tested.rollback();
|
||||
verify();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package org.springframework.ldap.support.transaction;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.DirContext;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.ldap.ContextSource;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
|
||||
public class TransactionAwareContextSourceProxy implements ContextSource {
|
||||
|
||||
private ContextSource target;
|
||||
|
||||
public TransactionAwareContextSourceProxy(ContextSource target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public DirContext getReadOnlyContext() throws DataAccessException {
|
||||
DirContextHolder contextHolder = (DirContextHolder) TransactionSynchronizationManager
|
||||
.getResource(target);
|
||||
DirContext ctx = null;
|
||||
|
||||
if (contextHolder != null) {
|
||||
ctx = contextHolder.getCtx();
|
||||
}
|
||||
|
||||
if (ctx == null) {
|
||||
ctx = target.getReadOnlyContext();
|
||||
if (contextHolder != null) {
|
||||
contextHolder.setCtx(ctx);
|
||||
}
|
||||
}
|
||||
return getTransactionAwareDirContextProxy(ctx, target);
|
||||
}
|
||||
|
||||
private DirContext getTransactionAwareDirContextProxy(DirContext context,
|
||||
ContextSource target) {
|
||||
return (DirContext) Proxy
|
||||
.newProxyInstance(DirContextProxy.class.getClassLoader(),
|
||||
new Class[] { DirContextProxy.class },
|
||||
new TransactionAwareDirContextInvocationHandler(
|
||||
context, target));
|
||||
|
||||
}
|
||||
|
||||
public DirContext getReadWriteContext() throws DataAccessException {
|
||||
throw new UnsupportedOperationException("Not implemented yet");
|
||||
}
|
||||
|
||||
static class TransactionAwareDirContextInvocationHandler implements
|
||||
InvocationHandler {
|
||||
private DirContext target;
|
||||
|
||||
private ContextSource contextSource;
|
||||
|
||||
public TransactionAwareDirContextInvocationHandler(DirContext target,
|
||||
ContextSource contextSource) {
|
||||
this.target = target;
|
||||
this.contextSource = contextSource;
|
||||
}
|
||||
|
||||
public Object invoke(Object proxy, Method method, Object[] args)
|
||||
throws Throwable {
|
||||
|
||||
if (method.getName().equals("getTargetContext")) {
|
||||
return target;
|
||||
} else if (method.getName().equals("equals")) {
|
||||
// Only consider equal when proxies are identical.
|
||||
return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
|
||||
} else if (method.getName().equals("hashCode")) {
|
||||
// Use hashCode of Connection proxy.
|
||||
return new Integer(hashCode());
|
||||
} else if (method.getName().equals("close")) {
|
||||
doCloseConnection(target, contextSource);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return method.invoke(target, args);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw e.getTargetException();
|
||||
}
|
||||
}
|
||||
|
||||
private void doCloseConnection(DirContext context,
|
||||
ContextSource contextSource) throws NamingException {
|
||||
DirContextHolder transactionContextHolder = (DirContextHolder) TransactionSynchronizationManager
|
||||
.getResource(contextSource);
|
||||
if (transactionContextHolder == null
|
||||
|| transactionContextHolder.getCtx() != context) {
|
||||
// This is not the transactional context or the transaction is
|
||||
// no longer active - we should close it.
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.springframework.ldap.support.transaction;
|
||||
|
||||
import javax.naming.Name;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.ldap.LdapOperations;
|
||||
|
||||
public class UnbindRollbackOperation implements
|
||||
CompensatingTransactionRollbackOperation {
|
||||
private static Log log = LogFactory.getLog(UnbindRollbackOperation.class);
|
||||
|
||||
private LdapOperations ldapOperations;
|
||||
|
||||
private Name dn;
|
||||
|
||||
public UnbindRollbackOperation(LdapOperations ldapOperations, Name dn) {
|
||||
this.ldapOperations = ldapOperations;
|
||||
this.dn = dn;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.ldap.support.transaction.CompensatingTransactionRollbackOperation#rollback()
|
||||
*/
|
||||
public void rollback() {
|
||||
try {
|
||||
ldapOperations.unbind(dn);
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to rollback, dn:" + dn.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the DN. Package private for testing purposes.
|
||||
*
|
||||
* @return the target DN.
|
||||
*/
|
||||
Name getDn() {
|
||||
return dn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the LdapOperations. Package private for testing purposes.
|
||||
*
|
||||
* @return the LdapOperations.
|
||||
*/
|
||||
LdapOperations getLdapOperations() {
|
||||
return ldapOperations;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package org.springframework.ldap.support.transaction;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.easymock.MockControl;
|
||||
import org.springframework.ldap.LdapOperations;
|
||||
import org.springframework.ldap.support.DistinguishedName;
|
||||
|
||||
public class UnbindRollbackOperationTest extends TestCase {
|
||||
private MockControl ldapOperationsControl;
|
||||
|
||||
private LdapOperations ldapOperationsMock;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
ldapOperationsControl = MockControl.createControl(LdapOperations.class);
|
||||
ldapOperationsMock = (LdapOperations) ldapOperationsControl.getMock();
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
ldapOperationsControl = null;
|
||||
ldapOperationsMock = null;
|
||||
}
|
||||
|
||||
protected void replay() {
|
||||
ldapOperationsControl.replay();
|
||||
}
|
||||
|
||||
protected void verify() {
|
||||
ldapOperationsControl.verify();
|
||||
}
|
||||
|
||||
public void testRollback() {
|
||||
DistinguishedName expectedDn = new DistinguishedName("cn=john doe");
|
||||
UnbindRollbackOperation tested = new UnbindRollbackOperation(ldapOperationsMock, expectedDn);
|
||||
|
||||
ldapOperationsMock.unbind(expectedDn);
|
||||
|
||||
replay();
|
||||
//perform teste
|
||||
tested.rollback();
|
||||
verify();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user