LDAP-29: Implement transaction support for Spring LDAP.

This commit is contained in:
Mattias Arthursson
2007-02-18 12:49:58 +00:00
parent 1ac17cca6b
commit 951c2e775d
55 changed files with 7 additions and 5742 deletions

View File

@@ -5,7 +5,6 @@
</configExtensions>
<configs>
<config>src/iutest/conf/ldapTemplateBaseSuffixTestContext.xml</config>
<config>src/itest/java/conf/ldapTemplateTransactionTestContext.xml</config>
<config>src/iutest/conf/ldapTemplateTestContext.xml</config>
</configs>
<configSets>
@@ -17,6 +16,13 @@
<config>src/iutest/conf/ldapTemplateBaseSuffixTestContext.xml</config>
</configs>
</configSet>
<configSet>
<name>iutesttransactions</name>
<allowBeanDefinitionOverriding>false</allowBeanDefinitionOverriding>
<incomplete>false</incomplete>
<configs>
</configs>
</configSet>
<configSet>
<name>iutest</name>
<allowBeanDefinitionOverriding>false</allowBeanDefinitionOverriding>
@@ -25,13 +31,5 @@
<config>src/iutest/conf/ldapTemplateTestContext.xml</config>
</configs>
</configSet>
<configSet>
<name>iutesttransactions</name>
<allowBeanDefinitionOverriding>false</allowBeanDefinitionOverriding>
<incomplete>false</incomplete>
<configs>
<config>src/itest/java/conf/ldapTemplateTransactionTestContext.xml</config>
</configs>
</configSet>
</configSets>
</beansProjectDescription>

View File

@@ -1,92 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<import resource="classpath:/conf/apacheDsContext.xml" />
<bean id="placeholderConfig"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location"
value="classpath:/conf/ldap.properties" />
</bean>
<bean id="contextSourceTarget"
class="org.springframework.ldap.core.support.LdapContextSource">
<property name="urls" value="${urls}" />
<property name="userDn" value="${userDn}" />
<property name="password" value="${password}" />
<property name="base" value="${base}" />
<property name="pooled" value="false" />
<property name="dirObjectFactory"
value="org.springframework.ldap.core.DefaultDirObjectFactory" />
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:mem:aname" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<bean id="contextSource"
class="org.springframework.ldap.transaction.core.TransactionAwareContextSourceProxy">
<constructor-arg ref="contextSourceTarget" />
</bean>
<bean id="ldapTemplate"
class="org.springframework.ldap.core.LdapTemplate">
<constructor-arg ref="contextSource" />
</bean>
<bean id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<!--
<bean id="ldapTransactionManager"
class="org.springframework.ldap.transaction.core.ContextSourceTransactionManager">
<property name="contextSource" ref="contextSourceTarget" />
</bean>
-->
<bean id="transactionManager"
class="org.springframework.ldap.transaction.core.ContextSourceAndDataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
<property name="contextSource" ref="contextSource" />
</bean>
<bean name="dummyDaoTarget"
class="org.springframework.ldap.transaction.core.LdapAndJdbcDummyDaoImpl">
<property name="ldapTemplate" ref="ldapTemplate" />
<property name="jdbcTemplate" ref="jdbcTemplate" />
</bean>
<bean name="dummyDao"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager"
ref="transactionManager" />
<property name="target" ref="dummyDaoTarget" />
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRES_NEW</prop>
</props>
</property>
</bean>
<!--
<bean name="dummyDao"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="dataSourceTransactionManager" />
<property name="target" ref="ldapDummyDao" />
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
-->
</beans>

View File

@@ -1,57 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<import resource="classpath:/conf/apacheDsContext.xml" />
<bean id="placeholderConfig"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location"
value="classpath:/conf/ldap.properties" />
</bean>
<bean id="contextSourceTarget"
class="org.springframework.ldap.core.support.LdapContextSource">
<property name="urls" value="${urls}" />
<property name="userDn" value="${userDn}" />
<property name="password" value="${password}" />
<property name="base" value="${base}" />
<property name="pooled" value="false" />
<property name="dirObjectFactory"
value="org.springframework.ldap.core.DefaultDirObjectFactory" />
</bean>
<bean id="contextSource"
class="org.springframework.ldap.transaction.core.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.core.ContextSourceTransactionManager">
<property name="contextSource" ref="contextSource" />
</bean>
<bean name="dummyDaoTarget"
class="org.springframework.ldap.transaction.core.LdapDummyDaoImpl">
<property name="ldapTemplate" ref="ldapTemplate" />
</bean>
<bean name="dummyDao"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager"
ref="transactionManager" />
<property name="target" ref="dummyDaoTarget" />
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRES_NEW</prop>
</props>
</property>
</bean>
</beans>

View File

@@ -1,374 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.ldap.LdapServerManager;
import org.springframework.ldap.NameNotFoundException;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.test.AbstractDependencyInjectionSpringContextTests;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* Integration tests for {@link ContextSourceAndDataSourceTransactionManager}.
*
* @author Mattias Arthursson
*/
public class ContextSourceAndDataSourceTransactionManagerIntegrationTest extends
AbstractDependencyInjectionSpringContextTests {
private static Log log = LogFactory
.getLog(ContextSourceAndDataSourceTransactionManagerIntegrationTest.class);
public ContextSourceAndDataSourceTransactionManagerIntegrationTest() {
setAutowireMode(AbstractDependencyInjectionSpringContextTests.AUTOWIRE_BY_NAME);
}
private DummyDao dummyDao;
private LdapTemplate ldapTemplate;
private JdbcTemplate jdbcTemplate;
private LdapServerManager ldapServerManager;
public void setLdapServerManager(LdapServerManager ldapServerManager) {
this.ldapServerManager = ldapServerManager;
}
public void setLdapTemplate(LdapTemplate ldapTemplate) {
this.ldapTemplate = ldapTemplate;
}
public void setDummyDao(DummyDao dummyDaoImpl) {
this.dummyDao = dummyDaoImpl;
}
protected String[] getConfigLocations() {
return new String[] { "conf/ldapAndJdbcTransactionTestContext.xml" };
}
protected void onSetUp() throws Exception {
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.clearSynchronization();
}
ldapServerManager.cleanAndSetup("setup_data.ldif");
jdbcTemplate
.execute("create table PERSON(fullname VARCHAR, lastname VARCHAR, description VARCHAR)");
jdbcTemplate.update("insert into PERSON values(?, ?, ?)", new Object[] {
"Some Person", "Person", "Sweden, Company1, Some Person" });
}
protected void onTearDown() throws Exception {
jdbcTemplate.execute("drop table PERSON");
}
public void testCreateWithException() {
try {
dummyDao.createWithException("Sweden", "company1",
"some testperson", "testperson", "some description");
fail("DummyException expected");
} catch (DummyException expected) {
assertTrue(true);
}
log.debug("Verifying result");
// Verify that no entry was created
try {
ldapTemplate.lookup("cn=some testperson, ou=company1, c=Sweden");
fail("NameNotFoundException expected");
} catch (NameNotFoundException expected) {
assertTrue(true);
}
try {
jdbcTemplate.queryForObject(
"select * from PERSON where fullname='some testperson'",
new RowMapper() {
public Object mapRow(ResultSet rs, int rowNum)
throws SQLException {
return null;
}
});
fail("EmptyResultDataAccessException expected");
} catch (EmptyResultDataAccessException expected) {
assertTrue(true);
}
}
public void testCreate() {
dummyDao.create("Sweden", "company1", "some testperson", "testperson",
"some description");
log.debug("Verifying result");
Object ldapResult = ldapTemplate
.lookup("cn=some testperson, ou=company1, c=Sweden");
Object dbResult = jdbcTemplate.queryForObject(
"select * from PERSON where fullname='some testperson'",
new RowMapper() {
public Object mapRow(ResultSet rs, int rowNum)
throws SQLException {
return new Object();
}
});
assertNotNull(ldapResult);
assertNotNull(dbResult);
}
public void testUpdateWithException() {
String dn = "cn=Some Person,ou=company1,c=Sweden";
try {
dummyDao.updateWithException(dn, "Some Person", "Updated Person",
"Updated description");
fail("DummyException expected");
} catch (DummyException expected) {
assertTrue(true);
}
log.debug("Verifying result");
Object ldapResult = ldapTemplate.lookup(dn, new AttributesMapper() {
public Object mapFromAttributes(Attributes attributes)
throws NamingException {
assertEquals("Person", attributes.get("sn").get());
assertEquals("Sweden, Company1, Some Person", attributes.get(
"description").get());
return new Object();
}
});
Object jdbcResult = jdbcTemplate.queryForObject(
"select * from PERSON where fullname=?",
new Object[] { "Some Person" }, new RowMapper() {
public Object mapRow(ResultSet rs, int rowNum)
throws SQLException {
assertEquals("Person", rs.getString("lastname"));
assertEquals("Sweden, Company1, Some Person", rs
.getString("description"));
return new Object();
}
});
assertNotNull(ldapResult);
assertNotNull(jdbcResult);
}
public void testUpdate() {
String dn = "cn=Some Person,ou=company1,c=Sweden";
dummyDao.update(dn, "Some Person", "Updated Person",
"Updated description");
log.debug("Verifying result");
Object ldapResult = ldapTemplate.lookup(dn, new AttributesMapper() {
public Object mapFromAttributes(Attributes attributes)
throws NamingException {
assertEquals("Updated Person", attributes.get("sn").get());
assertEquals("Updated description", attributes.get(
"description").get());
return new Object();
}
});
Object jdbcResult = jdbcTemplate.queryForObject(
"select * from PERSON where fullname=?",
new Object[] { "Some Person" }, new RowMapper() {
public Object mapRow(ResultSet rs, int rowNum)
throws SQLException {
assertEquals("Updated Person", rs.getString("lastname"));
assertEquals("Updated description", rs
.getString("description"));
return new Object();
}
});
assertNotNull(ldapResult);
assertNotNull(jdbcResult);
}
public void testUpdateAndRenameWithException() {
String dn = "cn=Some Person2,ou=company1,c=Sweden";
String newDn = "cn=Some Person2,ou=company2,c=Sweden";
try {
// Perform test
dummyDao.updateAndRenameWithException(dn, newDn,
"Updated description");
fail("DummyException expected");
} catch (DummyException expected) {
assertTrue(true);
}
// Verify that entry was not moved.
try {
ldapTemplate.lookup(newDn);
fail("NameNotFoundException expected");
} catch (NameNotFoundException expected) {
assertTrue(true);
}
// Verify that original entry was not updated.
Object object = ldapTemplate.lookup(dn, new AttributesMapper() {
public Object mapFromAttributes(Attributes attributes)
throws NamingException {
assertEquals("Sweden, Company1, Some Person2", attributes.get(
"description").get());
return new Object();
}
});
assertNotNull(object);
}
public void testUpdateAndRename() {
String dn = "cn=Some Person2,ou=company1,c=Sweden";
String newDn = "cn=Some Person2,ou=company2,c=Sweden";
// Perform test
dummyDao.updateAndRename(dn, newDn, "Updated description");
// Verify that entry was moved and updated.
Object object = ldapTemplate.lookup(newDn, new AttributesMapper() {
public Object mapFromAttributes(Attributes attributes)
throws NamingException {
assertEquals("Updated description", attributes.get(
"description").get());
return new Object();
}
});
assertNotNull(object);
}
public void testModifyAttributesWithException() {
String dn = "cn=Some Person,ou=company1,c=Sweden";
try {
// Perform test
dummyDao.modifyAttributesWithException(dn, "Updated lastname",
"Updated description");
fail("DummyException expected");
} catch (DummyException expected) {
assertTrue(true);
}
// Verify result - check that the operation was properly rolled back
Object result = ldapTemplate.lookup(dn, new AttributesMapper() {
public Object mapFromAttributes(Attributes attributes)
throws NamingException {
assertEquals("Person", attributes.get("sn").get());
assertEquals("Sweden, Company1, Some Person", attributes.get(
"description").get());
return new Object();
}
});
assertNotNull(result);
}
public void testModifyAttributes() {
String dn = "cn=Some Person,ou=company1,c=Sweden";
// Perform test
dummyDao
.modifyAttributes(dn, "Updated lastname", "Updated description");
// Verify result - check that the operation was not rolled back
Object result = ldapTemplate.lookup(dn, new AttributesMapper() {
public Object mapFromAttributes(Attributes attributes)
throws NamingException {
assertEquals("Updated lastname", attributes.get("sn").get());
assertEquals("Updated description", attributes.get(
"description").get());
return new Object();
}
});
assertNotNull(result);
}
public void testUnbindWithException() {
String dn = "cn=Some Person,ou=company1,c=Sweden";
try {
// Perform test
dummyDao.unbindWithException(dn, "Some Person");
fail("DummyException expected");
} catch (DummyException expected) {
assertTrue(true);
}
// Verify result - check that the operation was properly rolled back
Object ldapResult = ldapTemplate.lookup(dn, new AttributesMapper() {
public Object mapFromAttributes(Attributes attributes)
throws NamingException {
// Just verify that the entry still exists.
return new Object();
}
});
Object jdbcResult = jdbcTemplate.queryForObject(
"select * from PERSON where fullname=?",
new Object[] { "Some Person" }, new RowMapper() {
public Object mapRow(ResultSet rs, int rowNum)
throws SQLException {
// Just verify that the entry still exists.
return new Object();
}
});
assertNotNull(ldapResult);
assertNotNull(jdbcResult);
}
public void testUnbind() {
String dn = "cn=Some Person,ou=company1,c=Sweden";
// Perform test
dummyDao.unbind(dn, "Some Person");
try {
// Verify result - check that the operation was not rolled back
ldapTemplate.lookup(dn);
fail("NameNotFoundException expected");
} catch (NameNotFoundException expected) {
assertTrue(true);
}
try {
jdbcTemplate.queryForObject(
"select * from PERSON where fullname=?",
new Object[] { "Some Person" }, new RowMapper() {
public Object mapRow(ResultSet rs, int rowNum)
throws SQLException {
return null;
}
});
fail("EmptyResultDataAccessException expected");
} catch (EmptyResultDataAccessException expected) {
assertTrue(true);
}
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
}

View File

@@ -1,284 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.ldap.LdapServerManager;
import org.springframework.ldap.NameNotFoundException;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.test.AbstractDependencyInjectionSpringContextTests;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* Integration tests for {@link ContextSourceAndDataSourceTransactionManager}.
*
* @author Mattias Arthursson
*/
public class ContextSourceTransactionManagerIntegrationTest extends
AbstractDependencyInjectionSpringContextTests {
private static Log log = LogFactory
.getLog(ContextSourceTransactionManagerIntegrationTest.class);
public ContextSourceTransactionManagerIntegrationTest() {
setAutowireMode(AbstractDependencyInjectionSpringContextTests.AUTOWIRE_BY_NAME);
}
private DummyDao dummyDao;
private LdapTemplate ldapTemplate;
private LdapServerManager ldapServerManager;
public void setLdapServerManager(LdapServerManager ldapServerManager) {
this.ldapServerManager = ldapServerManager;
}
public void setLdapTemplate(LdapTemplate ldapTemplate) {
this.ldapTemplate = ldapTemplate;
}
public void setDummyDao(DummyDao dummyDaoImpl) {
this.dummyDao = dummyDaoImpl;
}
protected String[] getConfigLocations() {
return new String[] { "conf/ldapTemplateTransactionTestContext.xml" };
}
protected void onSetUp() throws Exception {
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.clearSynchronization();
}
ldapServerManager.cleanAndSetup("setup_data.ldif");
}
protected void onTearDown() throws Exception {
}
public void testCreateWithException() {
try {
dummyDao.createWithException("Sweden", "company1",
"some testperson", "testperson", "some description");
fail("DummyException expected");
} catch (DummyException expected) {
assertTrue(true);
}
log.debug("Verifying result");
// Verify that no entry was created
try {
ldapTemplate.lookup("cn=some testperson, ou=company1, c=Sweden");
fail("NameNotFoundException expected");
} catch (NameNotFoundException expected) {
assertTrue(true);
}
}
public void testCreate() {
dummyDao.create("Sweden", "company1", "some testperson", "testperson",
"some description");
log.debug("Verifying result");
Object ldapResult = ldapTemplate
.lookup("cn=some testperson, ou=company1, c=Sweden");
assertNotNull(ldapResult);
}
public void testUpdateWithException() {
String dn = "cn=Some Person,ou=company1,c=Sweden";
try {
dummyDao.updateWithException(dn, "Some Person", "Updated Person",
"Updated description");
fail("DummyException expected");
} catch (DummyException expected) {
assertTrue(true);
}
log.debug("Verifying result");
Object ldapResult = ldapTemplate.lookup(dn, new AttributesMapper() {
public Object mapFromAttributes(Attributes attributes)
throws NamingException {
assertEquals("Person", attributes.get("sn").get());
assertEquals("Sweden, Company1, Some Person", attributes.get(
"description").get());
return new Object();
}
});
assertNotNull(ldapResult);
}
public void testUpdate() {
String dn = "cn=Some Person,ou=company1,c=Sweden";
dummyDao.update(dn, "Some Person", "Updated Person",
"Updated description");
log.debug("Verifying result");
Object ldapResult = ldapTemplate.lookup(dn, new AttributesMapper() {
public Object mapFromAttributes(Attributes attributes)
throws NamingException {
assertEquals("Updated Person", attributes.get("sn").get());
assertEquals("Updated description", attributes.get(
"description").get());
return new Object();
}
});
assertNotNull(ldapResult);
}
public void testUpdateAndRenameWithException() {
String dn = "cn=Some Person2,ou=company1,c=Sweden";
String newDn = "cn=Some Person2,ou=company2,c=Sweden";
try {
// Perform test
dummyDao.updateAndRenameWithException(dn, newDn,
"Updated description");
fail("DummyException expected");
} catch (DummyException expected) {
assertTrue(true);
}
// Verify that entry was not moved.
try {
ldapTemplate.lookup(newDn);
fail("NameNotFoundException expected");
} catch (NameNotFoundException expected) {
assertTrue(true);
}
// Verify that original entry was not updated.
Object object = ldapTemplate.lookup(dn, new AttributesMapper() {
public Object mapFromAttributes(Attributes attributes)
throws NamingException {
assertEquals("Sweden, Company1, Some Person2", attributes.get(
"description").get());
return new Object();
}
});
assertNotNull(object);
}
public void testUpdateAndRename() {
String dn = "cn=Some Person2,ou=company1,c=Sweden";
String newDn = "cn=Some Person2,ou=company2,c=Sweden";
// Perform test
dummyDao.updateAndRename(dn, newDn, "Updated description");
// Verify that entry was moved and updated.
Object object = ldapTemplate.lookup(newDn, new AttributesMapper() {
public Object mapFromAttributes(Attributes attributes)
throws NamingException {
assertEquals("Updated description", attributes.get(
"description").get());
return new Object();
}
});
assertNotNull(object);
}
public void testModifyAttributesWithException() {
String dn = "cn=Some Person,ou=company1,c=Sweden";
try {
// Perform test
dummyDao.modifyAttributesWithException(dn, "Updated lastname",
"Updated description");
fail("DummyException expected");
} catch (DummyException expected) {
assertTrue(true);
}
// Verify result - check that the operation was properly rolled back
Object result = ldapTemplate.lookup(dn, new AttributesMapper() {
public Object mapFromAttributes(Attributes attributes)
throws NamingException {
assertEquals("Person", attributes.get("sn").get());
assertEquals("Sweden, Company1, Some Person", attributes.get(
"description").get());
return new Object();
}
});
assertNotNull(result);
}
public void testModifyAttributes() {
String dn = "cn=Some Person,ou=company1,c=Sweden";
// Perform test
dummyDao
.modifyAttributes(dn, "Updated lastname", "Updated description");
// Verify result - check that the operation was not rolled back
Object result = ldapTemplate.lookup(dn, new AttributesMapper() {
public Object mapFromAttributes(Attributes attributes)
throws NamingException {
assertEquals("Updated lastname", attributes.get("sn").get());
assertEquals("Updated description", attributes.get(
"description").get());
return new Object();
}
});
assertNotNull(result);
}
public void testUnbindWithException() {
String dn = "cn=Some Person,ou=company1,c=Sweden";
try {
// Perform test
dummyDao.unbindWithException(dn, "Some Person");
fail("DummyException expected");
} catch (DummyException expected) {
assertTrue(true);
}
// Verify result - check that the operation was properly rolled back
Object ldapResult = ldapTemplate.lookup(dn, new AttributesMapper() {
public Object mapFromAttributes(Attributes attributes)
throws NamingException {
// Just verify that the entry still exists.
return new Object();
}
});
assertNotNull(ldapResult);
}
public void testUnbind() {
String dn = "cn=Some Person,ou=company1,c=Sweden";
// Perform test
dummyDao.unbind(dn, "Some Person");
try {
// Verify result - check that the operation was not rolled back
ldapTemplate.lookup(dn);
fail("NameNotFoundException expected");
} catch (NameNotFoundException expected) {
assertTrue(true);
}
}
}

View File

@@ -1,44 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
public interface DummyDao {
void createWithException(String country, String company, String fullname,
String lastname, String description);
void create(String country, String company, String fullname,
String lastname, String description);
void update(String dn, String fullname, String lastname, String description);
void updateWithException(String dn, String fullname, String lastname,
String description);
void updateAndRename(String dn, String newDn, String description);
void updateAndRenameWithException(String dn, String newDn,
String description);
void modifyAttributes(String dn, String lastName, String description);
void modifyAttributesWithException(String dn, String lastName,
String description);
void unbind(String dn, String fullname);
void unbindWithException(String dn, String fullname);
}

View File

@@ -1,22 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
public class DummyException extends RuntimeException {
public DummyException(String message) {
super(message);
}
}

View File

@@ -1,24 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
public class DummyServiceImpl {
private DummyDao dummyDaoImpl;
public void setDummyDaoImpl(DummyDao dummyDaoImpl) {
this.dummyDaoImpl = dummyDaoImpl;
}
}

View File

@@ -1,178 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.ldap.core.DirContextAdapter;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.LdapTemplate;
public class LdapAndJdbcDummyDaoImpl implements DummyDao {
private LdapTemplate ldapTemplate;
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public void setLdapTemplate(LdapTemplate ldapTemplate) {
this.ldapTemplate = ldapTemplate;
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.transaction.core.DummyDao#createWithException(java.lang.String,
* java.lang.String, java.lang.String, java.lang.String,
* java.lang.String)
*/
public void createWithException(String country, String company,
String fullname, String lastname, String description) {
create(country, company, fullname, lastname, description);
throw new DummyException("This method failed");
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.transaction.core.DummyDao#create(java.lang.String,
* java.lang.String, java.lang.String, java.lang.String,
* java.lang.String)
*/
public void create(String country, String company, String fullname,
String lastname, String description) {
DistinguishedName dn = new DistinguishedName();
dn.add("c", country);
dn.add("ou", company);
dn.add("cn", fullname);
DirContextAdapter ctx = new DirContextAdapter();
ctx.setAttributeValues("objectclass", new String[] { "top", "person" });
ctx.setAttributeValue("cn", fullname);
ctx.setAttributeValue("sn", lastname);
ctx.setAttributeValue("description", description);
ldapTemplate.bind(dn, ctx, null);
jdbcTemplate.update("insert into PERSON values(?, ?, ?)", new Object[] {
fullname, lastname, description });
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.transaction.core.DummyDao#update(java.lang.String,
* java.lang.String, java.lang.String)
*/
public void update(String dn, String fullname, String lastname,
String description) {
DirContextAdapter ctx = (DirContextAdapter) ldapTemplate.lookup(dn);
ctx.setAttributeValue("sn", lastname);
ctx.setAttributeValue("description", description);
ctx.update();
ldapTemplate.rebind(dn, ctx, null);
jdbcTemplate
.update(
"update PERSON set lastname=?, description = ? where fullname = ?",
new Object[] { lastname, description, fullname });
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.transaction.core.DummyDao#updateWithException(java.lang.String,
* java.lang.String, java.lang.String)
*/
public void updateWithException(String dn, String fullname,
String lastname, String description) {
update(dn, fullname, lastname, description);
throw new DummyException("This method failed.");
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.transaction.core.DummyDao#updateAndRename(java.lang.String,
* java.lang.String, java.lang.String)
*/
public void updateAndRename(String dn, String newDn, String description) {
DirContextAdapter ctx = (DirContextAdapter) ldapTemplate.lookup(dn);
ctx.setAttributeValue("description", description);
ctx.update();
ldapTemplate.rebind(dn, ctx, null);
ldapTemplate.rename(dn, newDn);
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.transaction.core.DummyDao#updateAndRenameWithException(java.lang.String,
* java.lang.String, java.lang.String)
*/
public void updateAndRenameWithException(String dn, String newDn,
String description) {
updateAndRename(dn, newDn, description);
throw new DummyException("This method failed.");
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.transaction.core.DummyDao#modifyAttributes(java.lang.String,
* java.lang.String, java.lang.String)
*/
public void modifyAttributes(String dn, String lastName, String description) {
DirContextAdapter ctx = (DirContextAdapter) ldapTemplate.lookup(dn);
ctx.setAttributeValue("sn", lastName);
ctx.setAttributeValue("description", description);
ldapTemplate.modifyAttributes(dn, ctx.getModificationItems());
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.transaction.core.DummyDao#modifyAttributesWithException(java.lang.String,
* java.lang.String, java.lang.String)
*/
public void modifyAttributesWithException(String dn, String lastName,
String description) {
modifyAttributes(dn, lastName, description);
throw new DummyException("This method failed.");
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.transaction.core.DummyDao#unbind(java.lang.String)
*/
public void unbind(String dn, String fullname) {
ldapTemplate.unbind(dn);
jdbcTemplate.update("delete from PERSON where fullname=?",
new Object[] { fullname });
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.transaction.core.DummyDao#unbindWithException(java.lang.String)
*/
public void unbindWithException(String dn, String fullname) {
unbind(dn, fullname);
throw new DummyException("This operation failed.");
}
}

View File

@@ -1,163 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
import org.springframework.ldap.core.DirContextAdapter;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.LdapTemplate;
public class LdapDummyDaoImpl implements DummyDao {
private LdapTemplate ldapTemplate;
public void setLdapTemplate(LdapTemplate ldapTemplate) {
this.ldapTemplate = ldapTemplate;
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.transaction.core.DummyDao#createWithException(java.lang.String,
* java.lang.String, java.lang.String, java.lang.String,
* java.lang.String)
*/
public void createWithException(String country, String company,
String fullname, String lastname, String description) {
create(country, company, fullname, lastname, description);
throw new DummyException("This method failed");
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.transaction.core.DummyDao#create(java.lang.String,
* java.lang.String, java.lang.String, java.lang.String,
* java.lang.String)
*/
public void create(String country, String company, String fullname,
String lastname, String description) {
DistinguishedName dn = new DistinguishedName();
dn.add("c", country);
dn.add("ou", company);
dn.add("cn", fullname);
DirContextAdapter ctx = new DirContextAdapter();
ctx.setAttributeValues("objectclass", new String[] { "top", "person" });
ctx.setAttributeValue("cn", fullname);
ctx.setAttributeValue("sn", lastname);
ctx.setAttributeValue("description", description);
ldapTemplate.bind(dn, ctx, null);
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.transaction.core.DummyDao#update(java.lang.String,
* java.lang.String, java.lang.String)
*/
public void update(String dn, String fullname, String lastname,
String description) {
DirContextAdapter ctx = (DirContextAdapter) ldapTemplate.lookup(dn);
ctx.setAttributeValue("sn", lastname);
ctx.setAttributeValue("description", description);
ctx.update();
ldapTemplate.rebind(dn, ctx, null);
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.transaction.core.DummyDao#updateWithException(java.lang.String,
* java.lang.String, java.lang.String)
*/
public void updateWithException(String dn, String fullname,
String lastname, String description) {
update(dn, fullname, lastname, description);
throw new DummyException("This method failed.");
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.transaction.core.DummyDao#updateAndRename(java.lang.String,
* java.lang.String, java.lang.String)
*/
public void updateAndRename(String dn, String newDn, String description) {
DirContextAdapter ctx = (DirContextAdapter) ldapTemplate.lookup(dn);
ctx.setAttributeValue("description", description);
ctx.update();
ldapTemplate.rebind(dn, ctx, null);
ldapTemplate.rename(dn, newDn);
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.transaction.core.DummyDao#updateAndRenameWithException(java.lang.String,
* java.lang.String, java.lang.String)
*/
public void updateAndRenameWithException(String dn, String newDn,
String description) {
updateAndRename(dn, newDn, description);
throw new DummyException("This method failed.");
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.transaction.core.DummyDao#modifyAttributes(java.lang.String,
* java.lang.String, java.lang.String)
*/
public void modifyAttributes(String dn, String lastName, String description) {
DirContextAdapter ctx = (DirContextAdapter) ldapTemplate.lookup(dn);
ctx.setAttributeValue("sn", lastName);
ctx.setAttributeValue("description", description);
ldapTemplate.modifyAttributes(dn, ctx.getModificationItems());
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.transaction.core.DummyDao#modifyAttributesWithException(java.lang.String,
* java.lang.String, java.lang.String)
*/
public void modifyAttributesWithException(String dn, String lastName,
String description) {
modifyAttributes(dn, lastName, description);
throw new DummyException("This method failed.");
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.transaction.core.DummyDao#unbind(java.lang.String)
*/
public void unbind(String dn, String fullname) {
ldapTemplate.unbind(dn);
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.transaction.core.DummyDao#unbindWithException(java.lang.String)
*/
public void unbindWithException(String dn, String fullname) {
unbind(dn, fullname);
throw new DummyException("This operation failed.");
}
}

View File

@@ -1,60 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction;
/**
* Responsible for executing a single recorded operation as well as committing
* or rolling it back, depending on the transaction outcome. Instances of this
* interface are constructed by {@link CompensatingTransactionOperationRecorder}
* objects, supplying them with the information necessary for the respective
* operations.
* <p>
* The actual operations performed by the respective methods of this class might
* not be what would originally be expected. E.g. one would expect that the
* {@link #performOperation()} method of a
* CompensatingTransactionOperationExecutor implementation would actually delete
* the entry, leaving it for the {@link #rollback()} method to recreate it using
* data from the original entry. In an LDAP system for instance this will not be
* possible, because it might not be possible to retrieve all the stored data
* from the original entry. In that case, the {@link #performOperation()} method
* will instead move the entry to a temporary location and leave it for the
* {@link #commit()} method to actually remove the entry.
*
* @author Mattias Arthursson
*/
public interface CompensatingTransactionOperationExecutor {
/**
* Rollback the operation, restoring state of the target as it was before
* the operation was performed using the information supplied on creation of
* this instance.
*/
public void rollback();
/**
* Commit the operation. In many cases this will not require any work at all
* to be performed. However in some cases there will be interesting stuff to
* do. See class description for elaboration on this.
*/
public void commit();
/**
* Perform the operation. This will most often require performing the
* recorded operation, but in some cases the actual operation performed by
* this method might be something else. See class description for
* elaboration on this.
*/
public void performOperation();
}

View File

@@ -1,38 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction;
/**
* Factory interface for creating
* {@link CompensatingTransactionOperationRecorder} objects based on operation
* method names.
*
* @author Mattias Arthursson
* @see DefaultCompensatingTransactionOperationManager
*/
public interface CompensatingTransactionOperationFactory {
/**
* Create an appropriate {@link CompensatingTransactionOperationRecorder}
* instance corresponding to the supplied method name.
*
* @param method
* the method name to create a
* {@link CompensatingTransactionOperationRecorder} for.
* @return a new {@link CompensatingTransactionOperationRecorder} instance.
*/
public CompensatingTransactionOperationRecorder createRecordingOperation(
String method);
}

View File

@@ -1,52 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction;
/**
* A CompensatingTransactionOperationManager implementation records and performs
* operations that are to be performed within a compensating transaction and
* keeps track of compensating actions necessary for rolling back each
* individual operation.
*
* @author Mattias Arthursson
*
*/
public interface CompensatingTransactionOperationManager {
/**
* Indicates that the supplied operation (method name) is to be performed.
* This method is responsible for recording the current state (prior to the
* operation), performing the operation, and storing the necessary
* information to roll back or commit the performed operation.
*
* @param operation
* The method to be invoked.
* @param args
* Arguments supplied to the method.
*/
public void performOperation(String operation, Object[] args);
/**
* Rollback all recorded operations, by performing each of the recorded
* rollback operations.
*/
public void rollback();
/**
* Commit all recorded operations. In many cases this means doing nothing,
* but in some cases some temporary data will need to be removed.
*/
public void commit();
}

View File

@@ -1,40 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction;
/**
* An implementation of this interface is responsible for recording data and
* supplying a {@link CompensatingTransactionOperationExecutor} to be invoked
* for execution and compensating transaction management of the operation.
* Recording of an operation should not fail (throwing an Exception), but rather
* log the result.
*
* @author Mattias Arthursson
*/
public interface CompensatingTransactionOperationRecorder {
/**
* Record information about the operation performed and return a
* corresponding {@link CompensatingTransactionOperationExecutor} to be used
* if the operation would need to be rolled back.
*
* @param args
* The arguments that have been sent to the operation.
* @return A {@link CompensatingTransactionOperationExecutor} to be used if
* the recorded operation should need to be rolled back.
*/
public CompensatingTransactionOperationExecutor recordOperation(
Object[] args);
}

View File

@@ -1,118 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction;
import java.util.Stack;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Default implementation of {@link CompensatingTransactionOperationManager}.
* Manages a stack of {@link CompensatingTransactionOperationExecutor} objects
* and manages rollback of these in the reverse order.
*
* @author Mattias Arthursson
*/
public class DefaultCompensatingTransactionOperationManager implements
CompensatingTransactionOperationManager {
private static Log log = LogFactory
.getLog(DefaultCompensatingTransactionOperationManager.class);
private Stack rollbackOperations = new Stack();
private CompensatingTransactionOperationFactory operationFactory;
/**
* Set the {@link CompensatingTransactionOperationFactory} to use.
*
* @param operationFactory
* the {@link CompensatingTransactionOperationFactory}.
*/
public DefaultCompensatingTransactionOperationManager(
CompensatingTransactionOperationFactory operationFactory) {
this.operationFactory = operationFactory;
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationManager#operationPerformed(java.lang.String,
* java.lang.Object[])
*/
public void performOperation(String operation, Object[] args) {
CompensatingTransactionOperationRecorder recorder = operationFactory
.createRecordingOperation(operation);
CompensatingTransactionOperationExecutor executor = recorder
.recordOperation(args);
executor.performOperation();
// Don't push the executor until the actual operation passed.
rollbackOperations.push(executor);
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationManager#rollback()
*/
public void rollback() {
log.debug("Performing rollback");
while (!rollbackOperations.isEmpty()) {
CompensatingTransactionOperationExecutor rollbackOperation = (CompensatingTransactionOperationExecutor) rollbackOperations
.pop();
rollbackOperation.rollback();
}
}
/**
* Get the rollback operations. Package protected for testing purposes.
*
* @return the rollback operations.
*/
protected 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;
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationManager#commit()
*/
public void commit() {
log.debug("Performing rollback");
// TODO: Should this really be done in reverse order?
while (!rollbackOperations.isEmpty()) {
CompensatingTransactionOperationExecutor rollbackOperation = (CompensatingTransactionOperationExecutor) rollbackOperations
.pop();
rollbackOperation.commit();
}
}
}

View File

@@ -1,126 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
import javax.naming.Name;
import javax.naming.directory.Attributes;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.ldap.core.LdapOperations;
import org.springframework.ldap.transaction.CompensatingTransactionOperationExecutor;
/**
* A {@link CompensatingTransactionOperationExecutor} to manage a bind
* operation. Performs a bind in {@link #performOperation()}, a corresponding
* unbind in {@link #rollback()}, and nothing in {@link #commit()}.
*
* @author Mattias Arthursson
*/
public class BindOperationExecutor implements
CompensatingTransactionOperationExecutor {
private static Log log = LogFactory.getLog(BindOperationExecutor.class);
private LdapOperations ldapOperations;
private Name dn;
private Object originalObject;
private Attributes originalAttributes;
/**
* Constructor.
*
* @param ldapOperations
* {@link LdapOperations} to use for performing the rollback
* operation.
* @param dn
* DN of the entry to be unbound.
* @param originalObject
* original value sent to the 'object' parameter of the bind
* operation.
* @param originalAttributes
* original value sent to the 'attributes' parameter of the bind
* operation.
*/
public BindOperationExecutor(LdapOperations ldapOperations, Name dn,
Object originalObject, Attributes originalAttributes) {
this.ldapOperations = ldapOperations;
this.dn = dn;
this.originalObject = originalObject;
this.originalAttributes = originalAttributes;
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#rollback()
*/
public void rollback() {
try {
ldapOperations.unbind(dn);
} catch (Exception e) {
log.warn("Failed to rollback, dn:" + dn.toString(), e);
}
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#commit()
*/
public void commit() {
log.debug("Nothing to do in commit for bind operation");
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#performOperation()
*/
public void performOperation() {
log.debug("Performing bind operation");
ldapOperations.bind(dn, originalObject, originalAttributes);
}
/**
* 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;
}
Attributes getOriginalAttributes() {
return originalAttributes;
}
Object getOriginalObject() {
return originalObject;
}
}

View File

@@ -1,83 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
import javax.naming.Name;
import javax.naming.directory.Attributes;
import org.springframework.ldap.core.LdapOperations;
import org.springframework.ldap.transaction.CompensatingTransactionOperationExecutor;
import org.springframework.ldap.transaction.CompensatingTransactionOperationRecorder;
/**
* A {@link CompensatingTransactionOperationRecorder} to manage LDAP bind
* operations. The corresponding
* {@link CompensatingTransactionOperationExecutor} is
* {@link BindOperationExecutor}.
*
* @author Mattias Arthursson
*/
public class BindOperationRecorder implements
CompensatingTransactionOperationRecorder {
private LdapOperations ldapOperations;
/**
* Constructor.
*
* @param ldapOperations
* {@link LdapOperations} to use for supplying to the
* corresponding rollback operation.
*/
public BindOperationRecorder(LdapOperations ldapOperations) {
this.ldapOperations = ldapOperations;
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationRecorder#recordOperation(java.lang.Object[])
*/
public CompensatingTransactionOperationExecutor recordOperation(
Object[] args) {
if (args == null || args.length != 3) {
throw new IllegalArgumentException(
"Invalid arguments for bind operation");
}
Name dn = LdapUtils.getFirstArgumentAsName(args);
Object object = args[1];
Attributes attributes = null;
if (args[2] != null && !(args[2] instanceof Attributes)) {
throw new IllegalArgumentException(
"Invalid third argument to bind operation");
} else if (args[2] != null) {
attributes = (Attributes) args[2];
}
return new BindOperationExecutor(ldapOperations, dn, object,
attributes);
}
/**
* Get the LdapOperations. For testing purposes.s
*
* @return the LdapOperations.
*/
LdapOperations getLdapOperations() {
return ldapOperations;
}
}

View File

@@ -1,205 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.ldap.core.ContextSource;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionSuspensionNotSupportedException;
import org.springframework.transaction.support.DefaultTransactionStatus;
/**
* A Transaction Manager to manage LDAP and JDBC operations within the same
* transaction. Note that even though the same logical transaction is used, this
* is <b>not</b> a JTA XA transaction; no two-phase commit will be performed,
* and thus commit and rollback may result in unexpected results.
*
* @author Mattias Arthursson
*/
public class ContextSourceAndDataSourceTransactionManager extends
DataSourceTransactionManager {
private static final long serialVersionUID = 6832868697460384648L;
private ContextSourceTransactionManagerDelegate ldapManagerDelegate = new ContextSourceTransactionManagerDelegate();
public ContextSourceAndDataSourceTransactionManager() {
super();
// Override the default behaviour.
setNestedTransactionAllowed(false);
}
/*
* (non-Javadoc)
*
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager#isExistingTransaction(java.lang.Object)
*/
protected boolean isExistingTransaction(Object transaction) {
ContextSourceAndDataSourceTransactionObject actualTransactionObject = (ContextSourceAndDataSourceTransactionObject) transaction;
return super.isExistingTransaction(actualTransactionObject
.getDataSourceTransactionObject());
}
/*
* (non-Javadoc)
*
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager#doGetTransaction()
*/
protected Object doGetTransaction() throws TransactionException {
Object dataSourceTransactionObject = super.doGetTransaction();
Object contextSourceTransactionObject = ldapManagerDelegate
.doGetTransaction();
return new ContextSourceAndDataSourceTransactionObject(
contextSourceTransactionObject, dataSourceTransactionObject);
}
/*
* (non-Javadoc)
*
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin(java.lang.Object,
* org.springframework.transaction.TransactionDefinition)
*/
protected void doBegin(Object transaction, TransactionDefinition definition)
throws TransactionException {
ContextSourceAndDataSourceTransactionObject actualTransactionObject = (ContextSourceAndDataSourceTransactionObject) transaction;
super.doBegin(actualTransactionObject.getDataSourceTransactionObject(),
definition);
ldapManagerDelegate.doBegin(actualTransactionObject
.getLdapTransactionObject(), definition);
}
/*
* (non-Javadoc)
*
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager#doCleanupAfterCompletion(java.lang.Object)
*/
protected void doCleanupAfterCompletion(Object transaction) {
ContextSourceAndDataSourceTransactionObject actualTransactionObject = (ContextSourceAndDataSourceTransactionObject) transaction;
super.doCleanupAfterCompletion(actualTransactionObject
.getDataSourceTransactionObject());
ldapManagerDelegate.doCleanupAfterCompletion(actualTransactionObject
.getLdapTransactionObject());
}
/*
* (non-Javadoc)
*
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager#doCommit(org.springframework.transaction.support.DefaultTransactionStatus)
*/
protected void doCommit(DefaultTransactionStatus status)
throws TransactionException {
ContextSourceAndDataSourceTransactionObject actualTransactionObject = (ContextSourceAndDataSourceTransactionObject) status
.getTransaction();
try {
super.doCommit(new DefaultTransactionStatus(actualTransactionObject
.getDataSourceTransactionObject(), status
.isNewTransaction(), status.isNewSynchronization(), status
.isReadOnly(), status.isDebug(), status
.getSuspendedResources()));
} catch (TransactionException ex) {
if (isRollbackOnCommitFailure()) {
logger.debug("Failed to commit db resource, rethrowing", ex);
// If we are to rollback on commit failure, just rethrow the
// exception - this will cause a rollback to be performed on
// both resources.
throw ex;
} else {
logger
.warn("Failed to commit and resource is rollbackOnCommit not set -"
+ " proceeding to commit ldap resource.");
}
}
ldapManagerDelegate.doCommit(new DefaultTransactionStatus(
actualTransactionObject.getLdapTransactionObject(), status
.isNewTransaction(), status.isNewSynchronization(),
status.isReadOnly(), status.isDebug(), status
.getSuspendedResources()));
}
/*
* (non-Javadoc)
*
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager#doRollback(org.springframework.transaction.support.DefaultTransactionStatus)
*/
protected void doRollback(DefaultTransactionStatus status)
throws TransactionException {
ContextSourceAndDataSourceTransactionObject actualTransactionObject = (ContextSourceAndDataSourceTransactionObject) status
.getTransaction();
super.doRollback(new DefaultTransactionStatus(actualTransactionObject
.getDataSourceTransactionObject(), status.isNewTransaction(),
status.isNewSynchronization(), status.isReadOnly(), status
.isDebug(), status.getSuspendedResources()));
ldapManagerDelegate.doRollback(new DefaultTransactionStatus(
actualTransactionObject.getLdapTransactionObject(), status
.isNewTransaction(), status.isNewSynchronization(),
status.isReadOnly(), status.isDebug(), status
.getSuspendedResources()));
}
public ContextSource getContextSource() {
return ldapManagerDelegate.getContextSource();
}
public void setContextSource(ContextSource contextSource) {
ldapManagerDelegate.setContextSource(contextSource);
}
protected void setRenamingStrategy(
TempEntryRenamingStrategy renamingStrategy) {
ldapManagerDelegate.setRenamingStrategy(renamingStrategy);
}
private class ContextSourceAndDataSourceTransactionObject {
private Object ldapTransactionObject;
private Object dataSourceTransactionObject;
public ContextSourceAndDataSourceTransactionObject(
Object ldapTransactionObject, Object dataSourceTransactionObject) {
this.ldapTransactionObject = ldapTransactionObject;
this.dataSourceTransactionObject = dataSourceTransactionObject;
}
public Object getDataSourceTransactionObject() {
return dataSourceTransactionObject;
}
public Object getLdapTransactionObject() {
return ldapTransactionObject;
}
}
protected Object doSuspend(Object transaction) throws TransactionException {
throw new TransactionSuspensionNotSupportedException(
"Transaction manager [" + getClass().getName()
+ "] does not support transaction suspension");
}
protected void doResume(Object transaction, Object suspendedResources)
throws TransactionException {
throw new TransactionSuspensionNotSupportedException(
"Transaction manager [" + getClass().getName()
+ "] does not support transaction suspension");
}
}

View File

@@ -1,192 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
import org.springframework.ldap.core.ContextSource;
import org.springframework.ldap.transaction.CompensatingTransactionOperationExecutor;
import org.springframework.ldap.transaction.CompensatingTransactionOperationRecorder;
import org.springframework.ldap.transaction.DefaultCompensatingTransactionOperationManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.support.AbstractPlatformTransactionManager;
import org.springframework.transaction.support.DefaultTransactionStatus;
/**
* 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, i.e. should a transaction need to
* be rolled back this TransactionManager will try to restore the original
* original state using information recorded prior to each operation.
* <p>
* <b>NOTE:</b> The transactions provided by this TransactionManager are all
* <i>client side</i> and are by no means 'real' transactions, in the sense
* that we know them in the ordinary database world, e.g.:
* <ul>
* <li>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.</li>
* <li>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 transaction be
* rolled back, the outcome of this is undetermined, and may in the worst case
* result in total failure.</li>
* </ul>
* </p>
* <p>
* 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, particularly considering the total absence of
* transaction support which is normally the case working against LDAP servers.
* </p>
* <p>
* An LDAP transaction is tied to a {@link ContextSource}, to be supplied to
* the {@link #setContextSource(ContextSource)} method. While the actual
* ContextSource used by the target LdapTemplate instance needs to be of the
* type {@link TransactionAwareContextSourceProxy}, the ContextSource supplied
* to this class should be the actual target ContextSource.
* </p>
* <p>
* Using this TransactionManager along with
* {@link TransactionAwareContextSourceProxy} all modifying operations (bind,
* unbind, rebind, rename, modifyAttributes) in a transaction will be
* intercepted. Each modification has its corresponding
* {@link CompensatingTransactionOperationRecorder}, which collects the
* information necessary to perform a rollback and produces a
* {@link CompensatingTransactionOperationExecutor} which is then used to
* execute the actual operation and is later called for performing the commit or
* rollback.
* </p>
* <p>
* For several of the operations, performing a rollback is pretty
* straightforward. E.g. 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. E.g. an unbind operation is
* not possible to roll back by simply binding the entry back with the
* attributes retrieved from the original entry. This is because it might not be
* possible to get all the information from the original entry. Consequently,
* the {@link UnbindOperationExecutor} will move the original entry to a
* temporary location in its performOperation() method. In the commit() method
* we already know that everything went well, so we're free to unbind the entry,
* but 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
* {@link TempEntryRenamingStrategy} (default
* {@link DefaultTempEntryRenamingStrategy}), specified in
* {@link #setRenamingStrategy(TempEntryRenamingStrategy)}.
* </p>
* <p>
* The actual work of this Transaction Manager is delegated to a
* {@link 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.
* </p>
*
* @author Mattias Arthursson
*
* @see ContextSourceAndDataSourceTransactionManager
* @see ContextSourceTransactionManagerDelegate
* @see DefaultCompensatingTransactionOperationManager
* @see TempEntryRenamingStrategy
* @see TransactionAwareContextSourceProxy
*/
public class ContextSourceTransactionManager extends
AbstractPlatformTransactionManager {
private static final long serialVersionUID = 7138208218687237856L;
private ContextSourceTransactionManagerDelegate delegate = new ContextSourceTransactionManagerDelegate();
/*
* (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 {
delegate.doBegin(transaction, definition);
}
/*
* (non-Javadoc)
*
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#doCleanupAfterCompletion(java.lang.Object)
*/
protected void doCleanupAfterCompletion(Object transaction) {
delegate.doCleanupAfterCompletion(transaction);
}
/*
* (non-Javadoc)
*
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#doCommit(org.springframework.transaction.support.DefaultTransactionStatus)
*/
protected void doCommit(DefaultTransactionStatus status)
throws TransactionException {
delegate.doCommit(status);
}
/*
* (non-Javadoc)
*
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#doGetTransaction()
*/
protected Object doGetTransaction() throws TransactionException {
return delegate.doGetTransaction();
}
/*
* (non-Javadoc)
*
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#doRollback(org.springframework.transaction.support.DefaultTransactionStatus)
*/
protected void doRollback(DefaultTransactionStatus status)
throws TransactionException {
delegate.doRollback(status);
}
/**
* Get the ContextSource.
*
* @return the contextSource.
* @see ContextSourceTransactionManagerDelegate#getContextSource()
*/
public ContextSource getContextSource() {
return delegate.getContextSource();
}
/**
* Set the ContextSource.
*
* @param contextSource
* the ContextSource.
* @see ContextSourceTransactionManagerDelegate#setContextSource(ContextSource)
*/
public void setContextSource(ContextSource contextSource) {
delegate.setContextSource(contextSource);
}
/**
* Set the {@link TempEntryRenamingStrategy}.
*
* @param renamingStrategy
* the Renaming Strategy.
* @see ContextSourceTransactionManagerDelegate#setRenamingStrategy(TempEntryRenamingStrategy)
*/
public void setRenamingStrategy(TempEntryRenamingStrategy renamingStrategy) {
delegate.setRenamingStrategy(renamingStrategy);
}
}

View File

@@ -1,163 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.ldap.core.ContextSource;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.support.DefaultTransactionStatus;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* This delegate performs all the work for the
* {@link ContextSourceTransactionManager}. The work is delegated in order to
* be able to perform the exact same work for the LDAP part in
* {@link ContextSourceAndDataSourceTransactionManager}.
*
* @author Mattias Arthursson
* @see ContextSourceTransactionManager
* @see ContextSourceAndDataSourceTransactionManager
*/
public class ContextSourceTransactionManagerDelegate {
private static Log log = LogFactory
.getLog(ContextSourceTransactionManager.class);
private ContextSource contextSource;
private TempEntryRenamingStrategy renamingStrategy = new DefaultTempEntryRenamingStrategy();
/**
* Set the ContextSource to work on. Even though the actual ContextSource
* sent to the LdapTemplate instance should be a
* {@link TransactionAwareContextSourceProxy}, the one sent to this method
* should be the target of that proxy. If it is not, the target will be
* extracted and used instead.
*
* @param contextSource
* the ContextSource to work on.
*/
public void setContextSource(ContextSource contextSource) {
if (contextSource instanceof TransactionAwareContextSourceProxy) {
TransactionAwareContextSourceProxy proxy = (TransactionAwareContextSourceProxy) contextSource;
this.contextSource = proxy.getTarget();
} else {
this.contextSource = contextSource;
}
}
public ContextSource getContextSource() {
return contextSource;
}
/*
* (non-Javadoc)
*
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#doGetTransaction()
*/
public 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)
*/
public 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,
renamingStrategy);
txObject.setContextHolder(contextHolder);
TransactionSynchronizationManager.bindResource(getContextSource(),
contextHolder);
}
}
/*
* (non-Javadoc)
*
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#doCommit(org.springframework.transaction.support.DefaultTransactionStatus)
*/
public void doCommit(DefaultTransactionStatus status)
throws TransactionException {
ContextSourceTransactionObject txObject = (ContextSourceTransactionObject) status
.getTransaction();
txObject.getContextHolder().getTransactionDataManager().commit();
}
/*
* (non-Javadoc)
*
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#doRollback(org.springframework.transaction.support.DefaultTransactionStatus)
*/
public void doRollback(DefaultTransactionStatus status)
throws TransactionException {
ContextSourceTransactionObject txObject = (ContextSourceTransactionObject) status
.getTransaction();
txObject.getContextHolder().getTransactionDataManager().rollback();
}
/*
* (non-Javadoc)
*
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#doCleanupAfterCompletion(java.lang.Object)
*/
public void doCleanupAfterCompletion(Object transaction) {
log.debug("Cleaning stored ContextHolder");
TransactionSynchronizationManager.unbindResource(contextSource);
ContextSourceTransactionObject txObject = (ContextSourceTransactionObject) transaction;
DirContext ctx = txObject.getContextHolder().getCtx();
try {
log.debug("Closing target context");
ctx.close();
} catch (NamingException e) {
e.printStackTrace();
}
txObject.getContextHolder().clear();
}
/**
* Set the {@link TempEntryRenamingStrategy} to be used when renaming
* temporary entries in unbind and rebind operations. Default value is a
* {@link DefaultTempEntryRenamingStrategy}.
*
* @param renamingStrategy
* the {@link TempEntryRenamingStrategy} to use.
*/
public void setRenamingStrategy(TempEntryRenamingStrategy renamingStrategy) {
this.renamingStrategy = renamingStrategy;
}
}

View File

@@ -1,55 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
/**
* Transaction object for ContextSourceTransactionManager. Keeps a reference to
* the {@link DirContextHolder} associated with the current transaction.
*
* @author Mattias Arthursson
*/
public class ContextSourceTransactionObject {
private DirContextHolder contextHolder;
/**
* Constructor.
*
* @param contextHolder
* the DirContextHolder associated with the current transaction.
*/
public ContextSourceTransactionObject(DirContextHolder contextHolder) {
this.contextHolder = contextHolder;
}
/**
* Get the DirContextHolder.
*
* @return the DirContextHolder.
*/
public DirContextHolder getContextHolder() {
return contextHolder;
}
/**
* Set the DirContextHolder associated with the current transaction.s
*
* @param contextHolder
* the DirContextHolder associated with the current transaction.
*/
public void setContextHolder(DirContextHolder contextHolder) {
this.contextHolder = contextHolder;
}
}

View File

@@ -1,94 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
import java.util.List;
import javax.naming.Name;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.LdapRdn;
import org.springframework.ldap.core.LdapRdnComponent;
/**
* Default implementation of {@link TempEntryRenamingStrategy}. This
* implementation simply adds "_temp" to the leftmost (least siginificant part)
* of the name, e.g.:<br/>
*
* <code>
* cn=john doe, ou=company1, c=SE
* </code>
*
* becomes
*
* <code>
* cn=john doe_temp, ou=company1, c=SE
* </code>.
* <p>
* Note that using this strategy means that the entry remains in virtually the
* same location as where it originally resided. This means that searches later
* in the same transaction might return references to the temporary entry even
* though it should have been removed or rebound.
*
* @author Mattias Arthursson
*/
public class DefaultTempEntryRenamingStrategy implements
TempEntryRenamingStrategy {
/**
* The default temp entry suffix, &quot;_temp&quot;.
*/
public static final String DEFAULT_TEMP_SUFFIX = "_temp";
private String tempSuffix = DEFAULT_TEMP_SUFFIX;
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.transaction.TempEntryRenamingStrategy#getTemporaryName(javax.naming.Name)
*/
public Name getTemporaryName(Name originalName) {
DistinguishedName temporaryName = new DistinguishedName(originalName);
List names = temporaryName.getNames();
LdapRdn rdn = (LdapRdn) names.get(names.size() - 1);
LdapRdnComponent rdnComponent = rdn.getComponent();
String value = rdnComponent.getValue();
rdnComponent.setValue(value + DEFAULT_TEMP_SUFFIX);
return temporaryName;
}
/**
* Get the suffix that will be used for renaming temporary entries.
*
* @return the suffix.
*/
public String getTempSuffix() {
return tempSuffix;
}
/**
* Set the suffix to use for renaming temporary entries. Default value is
* {@link #DEFAULT_TEMP_SUFFIX}.
*
* @param tempSuffix
* the suffix.
*/
public void setTempSuffix(String tempSuffix) {
this.tempSuffix = tempSuffix;
}
}

View File

@@ -1,90 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
import java.util.List;
import javax.naming.Name;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.LdapRdn;
import org.springframework.ldap.core.LdapRdnComponent;
/**
* A {@link TempEntryRenamingStrategy} that moves the entry to a different
* subtree than the original entry. The specified subtree needs to be present in
* the LDAP tree; it will not be created and operations using this strategy will
* fail if it is not in place. However, this strategy is preferrable to
* {@link DefaultTempEntryRenamingStrategy}, as it makes it possible to have
* searches have the expected result even though the temporary entry still exits
* until the end of the transaction.
* <p>
* Example: If the specified <code>subtreeNode</code> is
* <code>ou=tempEntries</code> and the <code>originalName</code> is
* <code>cn=john doe, ou=company1, c=SE</code>, the result of
* {@link #getTemporaryName(Name)} will be
* <code>cn=john doe1, ou=tempEntries</code>. The &quot;1&quot; suffix is a
* sequence number needed to prevent potential collisions in the temporary
* storage.
*
* @author Mattias Arthursson
*
*/
public class DifferentSubtreeTempEntryRenamingStrategy implements
TempEntryRenamingStrategy {
private Name subtreeNode;
private static int nextSequenceNo = 1;
public DifferentSubtreeTempEntryRenamingStrategy(Name subtreeNode) {
this.subtreeNode = subtreeNode;
}
public Name getSubtreeNode() {
return subtreeNode;
}
public void setSubtreeNode(Name subtreeNode) {
this.subtreeNode = subtreeNode;
}
int getNextSequenceNo() {
return nextSequenceNo;
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.transaction.TempEntryRenamingStrategy#getTemporaryName(javax.naming.Name)
*/
public Name getTemporaryName(Name originalName) {
DistinguishedName tempName = new DistinguishedName(originalName);
List names = tempName.getNames();
LdapRdn rdn = (LdapRdn) names.get(names.size() - 1);
LdapRdnComponent component = rdn.getComponent();
LdapRdn newRdn;
synchronized (this) {
newRdn = new LdapRdn(component.getKey(), component.getValue()
+ nextSequenceNo++);
}
DistinguishedName newName = new DistinguishedName(subtreeNode);
newName.add(newRdn);
return newName;
}
}

View File

@@ -1,125 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
import javax.naming.directory.DirContext;
import org.springframework.ldap.transaction.CompensatingTransactionOperationFactory;
import org.springframework.ldap.transaction.CompensatingTransactionOperationManager;
import org.springframework.ldap.transaction.DefaultCompensatingTransactionOperationManager;
import org.springframework.transaction.support.ResourceHolderSupport;
/**
* Keeps track of the transaction DirContext. The same DirContext instance will
* be reused throughout a transaction. Also keeps a
* {@link CompensatingTransactionOperationManager}, responsible for performing
* operations and keeping track of all changes and storing information necessary
* for commit or rollback.
*
* @author Mattias Arthursson
*
*/
public class DirContextHolder extends ResourceHolderSupport {
private DirContext ctx;
private CompensatingTransactionOperationManager transactionDataManager;
private CompensatingTransactionOperationFactory operationFactory;
private TempEntryRenamingStrategy renamingStrategy;
/**
* Constructor.
*
* @param ctx
* The DirContext associated with the current transaction.
*/
public DirContextHolder(DirContext ctx,
TempEntryRenamingStrategy renamingStrategy) {
this.ctx = ctx;
this.renamingStrategy = renamingStrategy;
this.transactionDataManager = new DefaultCompensatingTransactionOperationManager(
createOperationFactory());
}
/**
* Set the DirContext associated with the current transaction.
*
* @param ctx
* The DirContext associated with the current transaction.
*/
public void setCtx(DirContext ctx) {
this.ctx = ctx;
this.transactionDataManager = new DefaultCompensatingTransactionOperationManager(
createOperationFactory());
}
/**
* Factory method to create a
* {@link CompensatingTransactionOperationFactory} using the settings and
* current state of this object.
*
* @return a new {@link LdapCompensatingTransactionOperationFactory}
* referncing the current transaction context.
*/
private CompensatingTransactionOperationFactory createOperationFactory() {
return new LdapCompensatingTransactionOperationFactory(ctx,
renamingStrategy);
}
/**
* Return the DirContext associated with the current transaction.
*/
public DirContext getCtx() {
return ctx;
}
public void clear() {
super.clear();
transactionDataManager = null;
operationFactory = null;
}
/**
* Get the CompensatingTransactionOperationManager to handle the data for
* the current transaction.
*
* @return the CompensatingTransactionOperationManager.
*/
public CompensatingTransactionOperationManager getTransactionDataManager() {
return transactionDataManager;
}
/**
* Set the CompensatingTransactionOperationManager. For testing purposes
* only.
*
* @param transactionDataManager
* the CompensatingTransactionOperationManager to use.
*/
void setTransactionDataManager(
CompensatingTransactionOperationManager transactionDataManager) {
this.transactionDataManager = transactionDataManager;
}
public CompensatingTransactionOperationFactory getOperationFactory() {
return operationFactory;
}
public TempEntryRenamingStrategy getRenamingStrategy() {
return renamingStrategy;
}
}

View File

@@ -1,33 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
import javax.naming.directory.DirContext;
/**
* Helper interface to be able to get hold of the target DirContext from proxies
* created by {@link TransactionAwareContextSourceProxy}.
*
* @author Mattias Arthursson
*/
public interface DirContextProxy extends DirContext {
/**
* Get the target DirContext of the proxy.
*
* @return the target DirContext.
*/
DirContext getTargetContext();
}

View File

@@ -1,183 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import javax.naming.directory.DirContext;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.ldap.core.ContextSource;
import org.springframework.ldap.core.LdapOperations;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.transaction.CompensatingTransactionOperationFactory;
import org.springframework.ldap.transaction.CompensatingTransactionOperationRecorder;
/**
* {@link CompensatingTransactionOperationRecorder} implementation for LDAP
* operations.
*
* @author Mattias Arthursson
*/
public class LdapCompensatingTransactionOperationFactory implements
CompensatingTransactionOperationFactory {
private static Log log = LogFactory
.getLog(LdapCompensatingTransactionOperationFactory.class);
private LdapOperations ldapOperations;
private TempEntryRenamingStrategy renamingStrategy;
/**
* Constructor.
*
* @param ctx
* The transactional DirContext.
*/
public LdapCompensatingTransactionOperationFactory(DirContext ctx,
TempEntryRenamingStrategy renamingStrategy) {
this.ldapOperations = new LdapTemplate(new SingleContextSource(ctx));
this.renamingStrategy = renamingStrategy;
}
public CompensatingTransactionOperationRecorder createRecordingOperation(
String operation) {
if (StringUtils.equals(operation, LdapUtils.BIND_METHOD_NAME)) {
log.debug("Bind operation recorded");
return new BindOperationRecorder(ldapOperations);
} else if (StringUtils.equals(operation, LdapUtils.REBIND_METHOD_NAME)) {
log.debug("Rebind operation recorded");
return new RebindOperationRecorder(ldapOperations, renamingStrategy);
} else if (StringUtils.equals(operation, LdapUtils.RENAME_METHOD_NAME)) {
log.debug("Rename operation recorded");
return new RenameOperationRecorder(ldapOperations);
} else if (StringUtils.equals(operation,
LdapUtils.MODIFY_ATTRIBUTES_METHOD_NAME)) {
return new ModifyAttributesOperationRecorder(ldapOperations);
} else if (StringUtils.equals(operation, LdapUtils.UNBIND_METHOD_NAME)) {
return new UnbindOperationRecorder(ldapOperations, renamingStrategy);
}
log
.warn("No suitable CompensatingTransactionOperationRecorder found for method "
+ operation + ". Operation will not be transacted.");
return new NullOperationRecorder();
}
/**
* A {@link ContextSource} implementation using returning
* {@link NonClosingDirContextInvocationHandler} proxies on the same
* DirContext instance for each call.
*
* @author Mattias Arthursson
*/
static class SingleContextSource implements ContextSource {
private DirContext ctx;
/**
* Constructor.
*
* @param ctx
* the target DirContext.
*/
public SingleContextSource(DirContext ctx) {
this.ctx = ctx;
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.ContextSource#getReadOnlyContext()
*/
public DirContext getReadOnlyContext() throws DataAccessException {
return getNonClosingDirContextProxy(ctx);
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.ContextSource#getReadWriteContext()
*/
public DirContext getReadWriteContext() throws DataAccessException {
return getNonClosingDirContextProxy(ctx);
}
private DirContext getNonClosingDirContextProxy(DirContext context) {
return (DirContext) Proxy.newProxyInstance(DirContextProxy.class
.getClassLoader(), new Class[] { DirContextProxy.class },
new NonClosingDirContextInvocationHandler(context));
}
}
/**
* A proxy for DirContext forwarding all operation to the target DirContext,
* but making sure that no <code>close</code> operations will be
* performed.
*
* @author Mattias Arthursson
*/
public static class NonClosingDirContextInvocationHandler implements
InvocationHandler {
private DirContext target;
public NonClosingDirContextInvocationHandler(DirContext target) {
this.target = target;
}
/*
* (non-Javadoc)
*
* @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,
* java.lang.reflect.Method, java.lang.Object[])
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
String methodName = method.getName();
if (methodName.equals("getTargetContext")) {
return target;
} else if (methodName.equals("equals")) {
// Only consider equal when proxies are identical.
return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
} else if (methodName.equals("hashCode")) {
// Use hashCode of Connection proxy.
return new Integer(proxy.hashCode());
} else if (methodName.equals("close")) {
// Never close the target context, as this class will only be
// used for operations concerning the compensating transactions.
return null;
}
try {
return method.invoke(target, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
}
void setLdapOperations(LdapOperations ldapOperations) {
this.ldapOperations = ldapOperations;
}
}

View File

@@ -1,165 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.ldap.core.ContextSource;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.transaction.CompensatingTransactionOperationManager;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
/**
* Common helper methods for Ldap operations.
*
* @author Mattias Arthursson
*/
public class LdapUtils {
private static Log log = LogFactory.getLog(LdapUtils.class);
public static final String REBIND_METHOD_NAME = "rebind";
public static final String BIND_METHOD_NAME = "bind";
public static final String RENAME_METHOD_NAME = "rename";
public static final String UNBIND_METHOD_NAME = "unbind";
public static final String MODIFY_ATTRIBUTES_METHOD_NAME = "modifyAttributes";
/**
* 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);
Object firstArg = args[0];
return getArgumentAsName(firstArg);
}
/**
* Get the argument as a Name.
*
* @param arg
* an argument supplied to an Ldap operation.
* @return a Name representation of the argument, or the Name itself if it
* is a Name.
*/
public static Name getArgumentAsName(Object arg) {
if (arg instanceof String) {
return new DistinguishedName((String) arg);
} else if (arg instanceof Name) {
return (Name) arg;
} else {
throw new IllegalArgumentException(
"First argument needs to be a Name or a String representation thereof");
}
}
/**
* Close the supplied context, but only if it is not associated with the
* current transaction.
*
* @param context
* the DirContext to close.
* @param contextSource
* the ContextSource bound to the transaction.
* @throws NamingException
*/
public static void doCloseConnection(DirContext context,
ContextSource contextSource) throws NamingException {
DirContextHolder transactionContextHolder = (DirContextHolder) TransactionSynchronizationManager
.getResource(contextSource);
if (transactionContextHolder == null
|| transactionContextHolder.getCtx() != context) {
log.debug("Closing context");
// This is not the transactional context or the transaction is
// no longer active - we should close it.
context.close();
} else {
log.debug("Leaving transactional context open");
}
}
/**
* Check whether the supplied method is a method for which transactions is
* supported (and which should be recorded for possible rollback later).
*
* @param methodName
* name of the method to check.
* @return <code>true</code> if this is a supported transaction operation,
* <code>false</code> otherwise.
*/
public static boolean isSupportedWriteTransactionOperation(String methodName) {
return (StringUtils.equals(methodName, BIND_METHOD_NAME)
|| StringUtils.equals(methodName, REBIND_METHOD_NAME)
|| StringUtils.equals(methodName, RENAME_METHOD_NAME)
|| StringUtils
.equals(methodName, MODIFY_ATTRIBUTES_METHOD_NAME) || StringUtils
.equals(methodName, UNBIND_METHOD_NAME));
}
/**
* Perform the specified operation, storing the state prior to the
* operation, to enable commit/rollback later.
*
* @param contextSource
* the ContextSource we are operating on.
* @param method
* name of the method to be invoked.
* @param args
* arguments with which the operation is invoked.
*/
public static void performOperation(ContextSource contextSource,
Method method, Object[] args) throws Throwable {
DirContextHolder transactionContextHolder = (DirContextHolder) TransactionSynchronizationManager
.getResource(contextSource);
if (transactionContextHolder != null) {
CompensatingTransactionOperationManager transactionDataManager = transactionContextHolder
.getTransactionDataManager();
transactionDataManager.performOperation(method.getName(), args);
} else {
// Perform the target operation
try {
method.invoke(transactionContextHolder.getCtx(), args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
}
}

View File

@@ -1,122 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
import javax.naming.Name;
import javax.naming.directory.ModificationItem;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.ldap.core.LdapOperations;
import org.springframework.ldap.transaction.CompensatingTransactionOperationExecutor;
/**
* A {@link CompensatingTransactionOperationExecutor} to manage a
* <code>modifyAttributes</code> operation. Performs a
* <code>modifyAttributes</code> in {@link #performOperation()}, a negating
* modifyAttributes in {@link #rollback()}, and nothing in {@link #commit()}.
*
* @author Mattias Arthursson
*/
public class ModifyAttributesOperationExecutor implements
CompensatingTransactionOperationExecutor {
private static Log log = LogFactory
.getLog(ModifyAttributesOperationExecutor.class);
private LdapOperations ldapOperations;
private Name dn;
private ModificationItem[] compensatingModifications;
private ModificationItem[] actualModifications;
/**
* Constructor.
*
* @param ldapOperations
* The {@link LdapOperations} to use to perform the rollback
* operation.
* @param dn
* the DN of the target entry.
* @param actualModifications
* the actual modificationItems that were sent to the
* modifyAttributes operation.
* @param compensatingModifications
* the ModificationItems to undo the recorded operation.
*/
public ModifyAttributesOperationExecutor(LdapOperations ldapOperations,
Name dn, ModificationItem[] actualModifications,
ModificationItem[] compensatingModifications) {
this.ldapOperations = ldapOperations;
this.dn = dn;
this.actualModifications = actualModifications;
this.compensatingModifications = compensatingModifications;
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#rollback()
*/
public void rollback() {
try {
log.debug("Rolling back modifyAttributes operation");
ldapOperations.modifyAttributes(dn, compensatingModifications);
} catch (Exception e) {
log
.warn("Failed to rollback ModifyAttributes operation, dn: "
+ dn);
}
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#commit()
*/
public void commit() {
log.debug("Nothing to do in commit for modifyAttributes");
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#performOperation()
*/
public void performOperation() {
log.debug("Performing modifyAttributes operation");
ldapOperations.modifyAttributes(dn, actualModifications);
}
Name getDn() {
return dn;
}
LdapOperations getLdapOperations() {
return ldapOperations;
}
ModificationItem[] getActualModifications() {
return actualModifications;
}
ModificationItem[] getCompensatingModifications() {
return compensatingModifications;
}
}

View File

@@ -1,166 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
import java.util.HashSet;
import java.util.Set;
import javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.DirContext;
import javax.naming.directory.ModificationItem;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapOperations;
import org.springframework.ldap.transaction.CompensatingTransactionOperationExecutor;
import org.springframework.ldap.transaction.CompensatingTransactionOperationRecorder;
import org.springframework.util.Assert;
/**
* A {@link CompensatingTransactionOperationRecorder} keeping track of
* modifyAttributes operations, creating corresponding
* {@link ModifyAttributesOperationExecutor} instances for rollback.
*
* @author Mattias Arthursson
*/
public class ModifyAttributesOperationRecorder implements
CompensatingTransactionOperationRecorder {
private LdapOperations ldapOperations;
public ModifyAttributesOperationRecorder(LdapOperations ldapOperations) {
this.ldapOperations = ldapOperations;
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationRecorder#recordOperation(java.lang.Object[])
*/
public CompensatingTransactionOperationExecutor recordOperation(
Object[] args) {
Assert.notNull(args);
Name dn = LdapUtils.getFirstArgumentAsName(args);
if (args.length != 2 || !(args[1] instanceof ModificationItem[])) {
throw new IllegalArgumentException(
"Unexpected arguments to ModifyAttributes operation");
}
ModificationItem[] incomingModifications = (ModificationItem[]) args[1];
Set set = new HashSet();
for (int i = 0; i < incomingModifications.length; i++) {
set.add(incomingModifications[i].getAttribute().getID());
}
// Get the current values of all referred Attributes.
String[] attributeNameArray = (String[]) set.toArray(new String[set
.size()]);
Attributes currentAttributes = (Attributes) ldapOperations.lookup(dn,
attributeNameArray, getAttributesMapper());
// Get a compensating ModificationItem for each of the incoming
// modification.
ModificationItem[] rollbackItems = new ModificationItem[incomingModifications.length];
for (int i = 0; i < incomingModifications.length; i++) {
rollbackItems[i] = getCompensatingModificationItem(
currentAttributes, incomingModifications[i]);
}
return new ModifyAttributesOperationExecutor(ldapOperations, dn,
incomingModifications, rollbackItems);
}
/**
* Get an {@link AttributesMapper} that just returns the supplied
* Attributes.
*
* @return the {@link AttributesMapper} to use for getting the current
* Attributes of the target DN.
*/
AttributesMapper getAttributesMapper() {
return new AttributesMapper() {
public Object mapFromAttributes(Attributes attributes)
throws NamingException {
return attributes;
}
};
}
/**
* Get a ModificationItem to use for rollback of the supplied modification.
*
* @param originalAttributes
* All Attributes of the target DN that are affected of any of
* the ModificationItems.
* @param modificationItem
* the ModificationItem to create a rollback item for.
* @return A ModificationItem to use for rollback of the supplied
* ModificationItem.
*/
protected ModificationItem getCompensatingModificationItem(
Attributes originalAttributes, ModificationItem modificationItem) {
Attribute modificationAttribute = modificationItem.getAttribute();
Attribute originalAttribute = originalAttributes
.get(modificationAttribute.getID());
if (modificationItem.getModificationOp() == DirContext.REMOVE_ATTRIBUTE) {
if (modificationAttribute.size() == 0) {
// If the modification attribute size it means that the
// Attribute should be removed entirely - we should store a
// ModificationItem to restore all present values for rollback.
return new ModificationItem(DirContext.ADD_ATTRIBUTE,
(Attribute) originalAttribute.clone());
} else {
// The rollback modification will be to re-add the removed
// attribute values.
return new ModificationItem(DirContext.ADD_ATTRIBUTE,
(Attribute) modificationAttribute.clone());
}
} else if (modificationItem.getModificationOp() == DirContext.REPLACE_ATTRIBUTE) {
if (originalAttribute != null) {
return new ModificationItem(DirContext.REPLACE_ATTRIBUTE,
(Attribute) originalAttribute.clone());
} else {
// The attribute doesn't previously exist - the rollback
// operation will be to remove the attribute.
return new ModificationItem(DirContext.REMOVE_ATTRIBUTE,
new BasicAttribute(modificationAttribute.getID()));
}
} else {
// An ADD_ATTRIBUTE operation
if (originalAttribute == null) {
// The attribute doesn't previously exist - the rollback
// operation will be to remove the attribute.
return new ModificationItem(DirContext.REMOVE_ATTRIBUTE,
new BasicAttribute(modificationAttribute.getID()));
} else {
// The attribute does exist before - we should store the
// previous value and it should be used for replacing in
// rollback.
return new ModificationItem(DirContext.REPLACE_ATTRIBUTE,
(Attribute) originalAttribute.clone());
}
}
}
LdapOperations getLdapOperations() {
return ldapOperations;
}
}

View File

@@ -1,49 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.ldap.transaction.CompensatingTransactionOperationExecutor;
/**
* A {@link CompensatingTransactionOperationExecutor} that performs nothing.
*
* @author Mattias Arthursson
*/
public class NullOperationExecutor implements
CompensatingTransactionOperationExecutor {
private static Log log = LogFactory.getLog(NullOperationExecutor.class);
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#rollback()
*/
public void rollback() {
log.info("Rolling back null operation");
}
public void commit() {
log.info("Committing back null operation");
}
public void performOperation() {
log.info("Performing null operation");
}
}

View File

@@ -1,45 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
import org.springframework.ldap.transaction.CompensatingTransactionOperationExecutor;
import org.springframework.ldap.transaction.CompensatingTransactionOperationManager;
import org.springframework.ldap.transaction.CompensatingTransactionOperationRecorder;
/**
* A {@link CompensatingTransactionOperationRecorder} performing nothing,
* returning a {@link NullOperationExecutor} regardless of the input. Instances
* of this class will be created if the
* {@link CompensatingTransactionOperationManager} cannot determine any appropriate
* {@link CompensatingTransactionOperationRecorder} for the current operation.
*
* @author Mattias Arthursson
*
*/
public class NullOperationRecorder implements
CompensatingTransactionOperationRecorder {
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationRecorder#recordOperation(java.lang.Object[])
*/
public CompensatingTransactionOperationExecutor recordOperation(
Object[] args) {
return new NullOperationExecutor();
}
}

View File

@@ -1,141 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
import javax.naming.Name;
import javax.naming.directory.Attributes;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.ldap.core.LdapOperations;
import org.springframework.ldap.transaction.CompensatingTransactionOperationExecutor;
/**
* A {@link CompensatingTransactionOperationExecutor} to manage a rebind
* operation. The methods in this class do not behave as expected, since it
* might be impossible to retrieve all the original attributes from the entry.
* Instead this class performs a <b>rename</b> in {@link #performOperation()},
* a negating rename in {@link #rollback()}, and the {@link #commit()}
* operation unbinds the original entry from its temporary location and binds a
* new entry to the original location using the attributes supplied to the
* original rebind opertaion.
*
* @author Mattias Arthursson
*/
public class RebindOperationExecutor implements
CompensatingTransactionOperationExecutor {
private static Log log = LogFactory.getLog(RebindOperationExecutor.class);
private LdapOperations ldapOperations;
private Name originalDn;
private Name temporaryDn;
private Object originalObject;
private Attributes originalAttributes;
/**
* Constructor.
*
* @param ldapOperations
* the {@link LdapOperations} to use to perform the rollback.
* @param originalDn
* The original DN of the entry to bind.
* @param temporaryDn
* The temporary DN of the entry.
* @param originalObject
* Original 'object' parameter sent to the rebind operation.
* @param originalAttributes
* Original 'attributes' parameter sent to the rebind operation
*/
public RebindOperationExecutor(LdapOperations ldapOperations,
Name originalDn, Name temporaryDn, Object originalObject,
Attributes originalAttributes) {
this.ldapOperations = ldapOperations;
this.originalDn = originalDn;
this.temporaryDn = temporaryDn;
this.originalObject = originalObject;
this.originalAttributes = originalAttributes;
}
/**
* Get the LdapOperations. Package private for testing purposes.
*
* @return the LdapOperations.
*/
LdapOperations getLdapOperations() {
return ldapOperations;
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#rollback()
*/
public void rollback() {
log.debug("Rolling back rebind operation");
try {
ldapOperations.unbind(originalDn);
ldapOperations.rename(temporaryDn, originalDn);
} catch (Exception e) {
log.warn("Failed to rollback operation, dn: " + originalDn
+ "; temporary DN: " + temporaryDn, e);
}
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#commit()
*/
public void commit() {
log.debug("Committing rebind operation");
ldapOperations.unbind(temporaryDn);
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#performOperation()
*/
public void performOperation() {
log.debug("Performing rebind operation - "
+ "renaming original entry and "
+ "binding new contents to entry.");
ldapOperations.rename(originalDn, temporaryDn);
ldapOperations.bind(originalDn, originalObject, originalAttributes);
}
Attributes getOriginalAttributes() {
return originalAttributes;
}
Name getOriginalDn() {
return originalDn;
}
Object getOriginalObject() {
return originalObject;
}
Name getTemporaryDn() {
return temporaryDn;
}
}

View File

@@ -1,94 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
import javax.naming.Name;
import javax.naming.directory.Attributes;
import org.springframework.ldap.core.LdapOperations;
import org.springframework.ldap.transaction.CompensatingTransactionOperationExecutor;
import org.springframework.ldap.transaction.CompensatingTransactionOperationRecorder;
/**
* A {@link CompensatingTransactionOperationRecorder} keeping track of a rebind
* operation. Creates {@link RebindOperationExecutor} objects in
* {@link #recordOperation(Object[])}.
*
* @author Mattias Arthursson
*/
public class RebindOperationRecorder implements
CompensatingTransactionOperationRecorder {
private LdapOperations ldapOperations;
private TempEntryRenamingStrategy renamingStrategy;
/**
* Constructor.
*
* @param ldapOperations
* {@link LdapOperations} to use for getting the rollback
* information and supply to the {@link RebindOperationExecutor}.
* @param the
* {@link TempEntryRenamingStrategy} to use for generating temp
* DNs.
*/
public RebindOperationRecorder(LdapOperations ldapOperations,
TempEntryRenamingStrategy renamingStrategy) {
this.ldapOperations = ldapOperations;
this.renamingStrategy = renamingStrategy;
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationRecorder#recordOperation(java.lang.Object[])
*/
public CompensatingTransactionOperationExecutor recordOperation(
Object[] args) {
if (args == null || args.length != 3) {
throw new IllegalArgumentException(
"Invalid arguments for bind operation");
}
Name dn = LdapUtils.getFirstArgumentAsName(args);
Object object = args[1];
Attributes attributes = null;
if (args[2] != null && !(args[2] instanceof Attributes)) {
throw new IllegalArgumentException(
"Invalid third argument to bind operation");
} else if (args[2] != null) {
attributes = (Attributes) args[2];
}
Name temporaryName = renamingStrategy.getTemporaryName(dn);
return new RebindOperationExecutor(ldapOperations, dn, temporaryName,
object, attributes);
}
/**
* Get the LdapOperations. For testing purposes.
*
* @return the LdapOperations.
*/
LdapOperations getLdapOperations() {
return ldapOperations;
}
public TempEntryRenamingStrategy getRenamingStrategy() {
return renamingStrategy;
}
}

View File

@@ -1,108 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
import javax.naming.Name;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.ldap.core.LdapOperations;
import org.springframework.ldap.transaction.CompensatingTransactionOperationExecutor;
/**
* A {@link CompensatingTransactionOperationExecutor} to manage a rename
* operation. Performs a rename operation in {@link #performOperation()}, a
* negating rename in {@link #rollback()}, and nothing in {@link #commit()}.
*
* @author Mattias Arthursson
*
*/
public class RenameOperationExecutor implements
CompensatingTransactionOperationExecutor {
private static Log log = LogFactory.getLog(RenameOperationExecutor.class);
private LdapOperations ldapOperations;
private Name newDn;
private Name originalDn;
/**
* Constructor.
*
* @param ldapOperations
* The {@link LdapOperations} to use for performing the rollback
* operation.
* @param originalDn
* DN that the entry was moved from in the recorded operation.
* @param newDn
* DN that the entry has been moved to in the recorded operation.
*/
public RenameOperationExecutor(LdapOperations ldapOperations,
Name originalDn, Name newDn) {
this.ldapOperations = ldapOperations;
this.originalDn = originalDn;
this.newDn = newDn;
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#rollback()
*/
public void rollback() {
log.debug("Rolling back rename operation");
try {
ldapOperations.rename(newDn, originalDn);
} catch (Exception e) {
log.warn("Unable to rollback rename operation. " + "originalDn: "
+ newDn + "; newDn: " + originalDn);
}
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#commit()
*/
public void commit() {
log.debug("Nothing to do in commit for rename operation");
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#performOperation()
*/
public void performOperation() {
log.debug("Performing rename operation");
ldapOperations.rename(originalDn, newDn);
}
Name getNewDn() {
return newDn;
}
LdapOperations getLdapOperations() {
return ldapOperations;
}
Name getOriginalDn() {
return originalDn;
}
}

View File

@@ -1,75 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
import javax.naming.Name;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.ldap.core.LdapOperations;
import org.springframework.ldap.transaction.CompensatingTransactionOperationExecutor;
import org.springframework.ldap.transaction.CompensatingTransactionOperationRecorder;
import org.springframework.util.Assert;
/**
* A {@link CompensatingTransactionOperationRecorder} for keeping track of
* rename operations. Creates {@link RebindOperationExecutor} objects for
* rolling back.
*
* @author Mattias Arthursson
*
*/
public class RenameOperationRecorder implements
CompensatingTransactionOperationRecorder {
private static Log log = LogFactory.getLog(RenameOperationRecorder.class);
private LdapOperations ldapOperations;
/**
* Constructor.
*
* @param ldapOperations
* The {@link LdapOperations} to supply to the created
* {@link RebindOperationExecutor} objects.
*/
public RenameOperationRecorder(LdapOperations ldapOperations) {
this.ldapOperations = ldapOperations;
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationRecorder#recordOperation(java.lang.Object[])
*/
public CompensatingTransactionOperationExecutor recordOperation(
Object[] args) {
log.debug("Storing rollback information for rename operation");
Assert.notEmpty(args);
if (args.length != 2) {
// This really shouldn't happen.
throw new IllegalArgumentException("Illegal argument length");
}
Name oldDn = LdapUtils.getArgumentAsName(args[0]);
Name newDn = LdapUtils.getArgumentAsName(args[1]);
return new RenameOperationExecutor(ldapOperations, oldDn, newDn);
}
LdapOperations getLdapOperations() {
return ldapOperations;
}
}

View File

@@ -1,37 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
import javax.naming.Name;
/**
* Interface for different strategies to rename temporary entries for unbind and
* rebind operations.
*
* @author Mattias Arthursson
*/
public interface TempEntryRenamingStrategy {
/**
* Get a temporary name for the current entry to be renamed to.
*
* @param originalName
* The original name of the entry.
* @return The name to which the entry should be temporarily renamed
* according to this strategy.
*/
public Name getTemporaryName(Name originalName);
}

View File

@@ -1,99 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
import java.lang.reflect.Proxy;
import javax.naming.directory.DirContext;
import org.springframework.dao.DataAccessException;
import org.springframework.ldap.core.ContextSource;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* A proxy for ContextSource to make sure that the returned DirContext objects
* are aware of the surrounding transactions, making sure that the DirContext is
* not closed during the transaction and that all modifying operations are
* recorded, keeping track of the corresponding rollback operations. All
* returned DirContext instances will be of the type
* {@link TransactionAwareDirContextInvocationHandler}.
*
* @author Mattias Arthursson
*/
public class TransactionAwareContextSourceProxy implements ContextSource {
private ContextSource target;
/**
* Constructor.
*
* @param target
* the target ContextSource.
*/
public TransactionAwareContextSourceProxy(ContextSource target) {
this.target = target;
}
/**
* Get the target ContextSource.
*
* @return the target ContextSource.
*/
public ContextSource getTarget() {
return target;
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.core.ContextSource#getReadOnlyContext()
*/
public DirContext getReadOnlyContext() throws DataAccessException {
return getReadWriteContext();
}
private DirContext getTransactionAwareDirContextProxy(DirContext context,
ContextSource target) {
return (DirContext) Proxy
.newProxyInstance(DirContextProxy.class.getClassLoader(),
new Class[] { DirContextProxy.class },
new TransactionAwareDirContextInvocationHandler(
context, target));
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.core.ContextSource#getReadWriteContext()
*/
public DirContext getReadWriteContext() throws DataAccessException {
DirContextHolder contextHolder = (DirContextHolder) TransactionSynchronizationManager
.getResource(target);
DirContext ctx = null;
if (contextHolder != null) {
ctx = contextHolder.getCtx();
}
if (ctx == null) {
ctx = target.getReadWriteContext();
if (contextHolder != null) {
contextHolder.setCtx(ctx);
}
}
return getTransactionAwareDirContextProxy(ctx, target);
}
}

View File

@@ -1,88 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.naming.directory.DirContext;
import org.springframework.ldap.core.ContextSource;
/**
* Proxy implementation for DirContext, making sure that the instance is not
* closed during a transaction, and that all modifying operations are recorded,
* storing compensating rollback operations for them.
*
* @author Mattias Arthursson
*/
public class TransactionAwareDirContextInvocationHandler implements
InvocationHandler {
private DirContext target;
private ContextSource contextSource;
/**
* Constructor.
*
* @param target
* The target DirContext.
* @param contextSource
* The transactional ContextSource, needed to get hold of the
* current transaction's {@link DirContextHolder}.
*/
public TransactionAwareDirContextInvocationHandler(DirContext target,
ContextSource contextSource) {
this.target = target;
this.contextSource = contextSource;
}
/*
* (non-Javadoc)
*
* @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,
* java.lang.reflect.Method, java.lang.Object[])
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
String methodName = method.getName();
if (methodName.equals("getTargetContext")) {
return target;
} else if (methodName.equals("equals")) {
// Only consider equal when proxies are identical.
return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
} else if (methodName.equals("hashCode")) {
// Use hashCode of Connection proxy.
return new Integer(proxy.hashCode());
} else if (methodName.equals("close")) {
LdapUtils.doCloseConnection(target, contextSource);
return null;
} else if (LdapUtils.isSupportedWriteTransactionOperation(methodName)) {
// Store transaction data and allow operation to proceed.
LdapUtils.performOperation(contextSource, method, args);
return null;
} else {
try {
return method.invoke(target, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
}
}

View File

@@ -1,117 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
import javax.naming.Name;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.ldap.core.LdapOperations;
import org.springframework.ldap.transaction.CompensatingTransactionOperationExecutor;
/**
* A {@link CompensatingTransactionOperationExecutor} to manage an unbind
* operation. The methods in this class do not behave as expected, since it
* might be impossible to retrieve all the original attributes from the entry.
* Instead this class performs a <b>rename</b> in {@link #performOperation()},
* a negating rename in {@link #rollback()}, and {@link #commit()} unbinds the
* entry from its temporary location.
*
* @author Mattias Arthursson
*/
public class UnbindOperationExecutor implements
CompensatingTransactionOperationExecutor {
private static Log log = LogFactory.getLog(UnbindOperationExecutor.class);
private LdapOperations ldapOperations;
private Name originalDn;
private Name temporaryDn;
/**
* Constructor.
*
* @param ldapOperations
* The {@link LdapOperations} to use for performing the rollback
* operation.
* @param originalDn
* The original DN of the entry to be removed.
* @param temporaryDn
* Temporary DN of the entry to be removed; this is where the
* entry is temporarily stored during the transaction.
*/
public UnbindOperationExecutor(LdapOperations ldapOperations,
Name originalDn, Name temporaryDn) {
this.ldapOperations = ldapOperations;
this.originalDn = originalDn;
this.temporaryDn = temporaryDn;
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#rollback()
*/
public void rollback() {
try {
ldapOperations.rename(temporaryDn, originalDn);
} catch (Exception e) {
log.warn("Filed to rollback unbind operation, temporaryDn: "
+ temporaryDn + "; originalDn: " + originalDn);
}
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#commit()
*/
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#commit()
*/
public void commit() {
log.debug("Committing unbind operation - unbinding temporary entry");
ldapOperations.unbind(temporaryDn);
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationExecutor#performOperation()
*/
public void performOperation() {
log.debug("Performing operation for unbind -"
+ " renaming to temporary entry.");
ldapOperations.rename(originalDn, temporaryDn);
}
LdapOperations getLdapOperations() {
return ldapOperations;
}
Name getOriginalDn() {
return originalDn;
}
Name getTemporaryDn() {
return temporaryDn;
}
}

View File

@@ -1,75 +0,0 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ldap.transaction.core;
import javax.naming.Name;
import org.springframework.ldap.core.LdapOperations;
import org.springframework.ldap.transaction.CompensatingTransactionOperationExecutor;
import org.springframework.ldap.transaction.CompensatingTransactionOperationRecorder;
/**
* {@link CompensatingTransactionOperationRecorder} to keep track of unbind
* operations. This class creates {@link UnbindOperationExecutor} objects for
* rollback.
*
* @author Mattias Arthursson
*/
public class UnbindOperationRecorder implements
CompensatingTransactionOperationRecorder {
private LdapOperations ldapOperations;
private TempEntryRenamingStrategy renamingStrategy;
/**
* Constructor.
*
* @param ldapOperations
* {@link LdapOperations} to use for getting the data prior to
* unbinding the entry and to supply to the
* {@link UnbindOperationExecutor} for rollback.
* @param renamingStrategy
* the {@link TempEntryRenamingStrategy} to use when generating
* DNs for temporary entries.
*/
public UnbindOperationRecorder(LdapOperations ldapOperations,
TempEntryRenamingStrategy renamingStrategy) {
this.ldapOperations = ldapOperations;
this.renamingStrategy = renamingStrategy;
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.support.transaction.CompensatingTransactionOperationRecorder#recordOperation(java.lang.Object[])
*/
public CompensatingTransactionOperationExecutor recordOperation(
Object[] args) {
Name dn = LdapUtils.getFirstArgumentAsName(args);
Name temporaryDn = renamingStrategy.getTemporaryName(dn);
return new UnbindOperationExecutor(ldapOperations, dn, temporaryDn);
}
LdapOperations getLdapOperations() {
return ldapOperations;
}
public TempEntryRenamingStrategy getRenamingStrategy() {
return renamingStrategy;
}
}

View File

@@ -1,116 +0,0 @@
package org.springframework.ldap.transaction;
import java.util.Stack;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.ldap.transaction.CompensatingTransactionOperationExecutor;
import org.springframework.ldap.transaction.CompensatingTransactionOperationFactory;
import org.springframework.ldap.transaction.CompensatingTransactionOperationRecorder;
import org.springframework.ldap.transaction.DefaultCompensatingTransactionOperationManager;
public class DefaultCompensatingTransactionOperationManagerTest extends
TestCase {
private MockControl operationExecutorControl;
private CompensatingTransactionOperationExecutor operationExecutorMock;
private MockControl operationFactoryControl;
private CompensatingTransactionOperationFactory operationFactoryMock;
private MockControl operationRecorderControl;
private CompensatingTransactionOperationRecorder operationRecorderMock;
protected void setUp() throws Exception {
super.setUp();
operationExecutorControl = MockControl
.createControl(CompensatingTransactionOperationExecutor.class);
operationExecutorMock = (CompensatingTransactionOperationExecutor) operationExecutorControl
.getMock();
operationFactoryControl = MockControl
.createControl(CompensatingTransactionOperationFactory.class);
operationFactoryMock = (CompensatingTransactionOperationFactory) operationFactoryControl
.getMock();
operationRecorderControl = MockControl
.createControl(CompensatingTransactionOperationRecorder.class);
operationRecorderMock = (CompensatingTransactionOperationRecorder) operationRecorderControl
.getMock();
}
protected void tearDown() throws Exception {
super.tearDown();
operationExecutorControl = null;
operationExecutorMock = null;
operationFactoryControl = null;
operationFactoryMock = null;
operationRecorderControl = null;
operationRecorderMock = null;
}
protected void replay() {
operationExecutorControl.replay();
operationFactoryControl.replay();
operationRecorderControl.replay();
}
protected void verify() {
operationExecutorControl.verify();
operationFactoryControl.verify();
operationRecorderControl.verify();
}
public void testPerformOperation() {
Object[] expectedArgs = new Object[0];
operationFactoryControl
.expectAndReturn(operationFactoryMock
.createRecordingOperation("some method"),
operationRecorderMock);
operationRecorderControl.expectAndReturn(operationRecorderMock
.recordOperation(expectedArgs), operationExecutorMock);
operationExecutorMock.performOperation();
DefaultCompensatingTransactionOperationManager tested = new DefaultCompensatingTransactionOperationManager(
operationFactoryMock);
replay();
tested.performOperation("some method", expectedArgs);
verify();
Stack result = tested.getRollbackOperations();
assertFalse(result.isEmpty());
assertSame(operationExecutorMock, result.peek());
}
public void testRollback() {
DefaultCompensatingTransactionOperationManager tested = new DefaultCompensatingTransactionOperationManager(
operationFactoryMock);
tested.getRollbackOperations().push(operationExecutorMock);
operationExecutorMock.rollback();
replay();
tested.rollback();
verify();
}
public void testCommit() {
DefaultCompensatingTransactionOperationManager tested = new DefaultCompensatingTransactionOperationManager(
operationFactoryMock);
tested.getRollbackOperations().push(operationExecutorMock);
operationExecutorMock.commit();
replay();
tested.commit();
verify();
}
}

View File

@@ -1,80 +0,0 @@
package org.springframework.ldap.transaction.core;
import javax.naming.directory.BasicAttributes;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.LdapOperations;
import org.springframework.ldap.transaction.core.BindOperationExecutor;
public class BindOperationExecutorTest 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 testPerformOperation() {
DistinguishedName expectedDn = new DistinguishedName("cn=john doe");
Object expectedObject = new Object();
BasicAttributes expectedAttributes = new BasicAttributes();
BindOperationExecutor tested = new BindOperationExecutor(
ldapOperationsMock, expectedDn, expectedObject,
expectedAttributes);
ldapOperationsMock.bind(expectedDn, expectedObject, expectedAttributes);
replay();
// perform teste
tested.performOperation();
verify();
}
public void testCommit() {
DistinguishedName expectedDn = new DistinguishedName("cn=john doe");
Object expectedObject = new Object();
BasicAttributes expectedAttributes = new BasicAttributes();
BindOperationExecutor tested = new BindOperationExecutor(
ldapOperationsMock, expectedDn, expectedObject,
expectedAttributes);
// Nothing to do here.
replay();
// perform teste
tested.commit();
verify();
}
public void testRollback() {
DistinguishedName expectedDn = new DistinguishedName("cn=john doe");
BindOperationExecutor tested = new BindOperationExecutor(
ldapOperationsMock, expectedDn, null, null);
ldapOperationsMock.unbind(expectedDn);
replay();
// perform teste
tested.rollback();
verify();
}
}

View File

@@ -1,83 +0,0 @@
package org.springframework.ldap.transaction.core;
import javax.naming.directory.BasicAttributes;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.LdapOperations;
import org.springframework.ldap.transaction.CompensatingTransactionOperationExecutor;
import org.springframework.ldap.transaction.core.BindOperationExecutor;
import org.springframework.ldap.transaction.core.BindOperationRecorder;
public class BindOperationRecorderTest 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;
}
public void testRecordOperation_DistinguishedName() {
BindOperationRecorder tested = new BindOperationRecorder(
ldapOperationsMock);
DistinguishedName expectedDn = new DistinguishedName("cn=John Doe");
Object expectedObject = new Object();
BasicAttributes expectedAttributes = new BasicAttributes();
// Perform test.
CompensatingTransactionOperationExecutor operation = tested
.recordOperation(new Object[] { expectedDn, expectedObject,
expectedAttributes });
assertTrue(operation instanceof BindOperationExecutor);
BindOperationExecutor rollbackOperation = (BindOperationExecutor) operation;
assertSame(expectedDn, rollbackOperation.getDn());
assertSame(ldapOperationsMock, rollbackOperation.getLdapOperations());
assertSame(expectedObject, rollbackOperation.getOriginalObject());
assertSame(expectedAttributes, rollbackOperation
.getOriginalAttributes());
}
public void testPerformOperation_String() {
BindOperationRecorder tested = new BindOperationRecorder(
ldapOperationsMock);
String expectedDn = "cn=John Doe";
Object expectedObject = new Object();
BasicAttributes expectedAttributes = new BasicAttributes();
// Perform test.
CompensatingTransactionOperationExecutor operation = tested
.recordOperation(new Object[] { expectedDn, expectedObject,
expectedAttributes });
assertTrue(operation instanceof BindOperationExecutor);
BindOperationExecutor rollbackOperation = (BindOperationExecutor) operation;
assertEquals(expectedDn, rollbackOperation.getDn().toString());
assertSame(ldapOperationsMock, rollbackOperation.getLdapOperations());
}
public void testPerformOperation_Invalid() {
BindOperationRecorder tested = new BindOperationRecorder(
ldapOperationsMock);
Object expectedDn = new Object();
try {
// Perform test.
tested.recordOperation(new Object[] { expectedDn });
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException expected) {
assertTrue(true);
}
}
}

View File

@@ -1,187 +0,0 @@
package org.springframework.ldap.transaction.core;
import javax.naming.directory.DirContext;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.ldap.core.ContextSource;
import org.springframework.ldap.transaction.CompensatingTransactionOperationManager;
import org.springframework.ldap.transaction.core.ContextSourceTransactionManager;
import org.springframework.ldap.transaction.core.ContextSourceTransactionObject;
import org.springframework.ldap.transaction.core.DirContextHolder;
import org.springframework.ldap.transaction.core.TempEntryRenamingStrategy;
import org.springframework.ldap.transaction.core.TransactionAwareContextSourceProxy;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.support.DefaultTransactionStatus;
import org.springframework.transaction.support.TransactionSynchronizationManager;
public class ContextSourceTransactionManagerTest extends TestCase {
private MockControl contextSourceControl;
private ContextSource contextSourceMock;
private MockControl contextControl;
private DirContext contextMock;
private ContextSourceTransactionManager tested;
private MockControl transactionDefinitionControl;
private MockControl transactionDataManagerControl;
private CompensatingTransactionOperationManager transactionDataManagerMock;
private TransactionDefinition transactionDefinitionMock;
private MockControl renamingStrategyControl;
private TempEntryRenamingStrategy renamingStrategyMock;
protected void setUp() throws Exception {
super.setUp();
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.clearSynchronization();
}
contextSourceControl = MockControl.createControl(ContextSource.class);
contextSourceMock = (ContextSource) contextSourceControl.getMock();
contextControl = MockControl.createControl(DirContext.class);
contextMock = (DirContext) contextControl.getMock();
transactionDefinitionControl = MockControl
.createControl(TransactionDefinition.class);
transactionDefinitionMock = (TransactionDefinition) transactionDefinitionControl
.getMock();
transactionDataManagerControl = MockControl
.createControl(CompensatingTransactionOperationManager.class);
transactionDataManagerMock = (CompensatingTransactionOperationManager) transactionDataManagerControl
.getMock();
renamingStrategyControl = MockControl
.createControl(TempEntryRenamingStrategy.class);
renamingStrategyMock = (TempEntryRenamingStrategy) renamingStrategyControl
.getMock();
tested = new ContextSourceTransactionManager();
tested.setContextSource(contextSourceMock);
tested.setRenamingStrategy(renamingStrategyMock);
}
protected void tearDown() throws Exception {
super.tearDown();
contextControl = null;
contextMock = null;
contextSourceControl = null;
contextSourceMock = null;
transactionDefinitionControl = null;
transactionDefinitionMock = null;
transactionDataManagerControl = null;
transactionDataManagerMock = null;
renamingStrategyControl = null;
renamingStrategyMock = null;
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.clearSynchronization();
}
}
public void testDoGetTransaction() {
Object result = tested.doGetTransaction();
assertNotNull(result);
assertTrue(result instanceof ContextSourceTransactionObject);
ContextSourceTransactionObject transactionObject = (ContextSourceTransactionObject) result;
assertNull(transactionObject.getContextHolder());
}
public void testDoGetTransactionTransactionActive() {
DirContextHolder expectedContextHolder = new DirContextHolder(null,
null);
TransactionSynchronizationManager.bindResource(contextSourceMock,
expectedContextHolder);
Object result = tested.doGetTransaction();
assertSame(expectedContextHolder,
((ContextSourceTransactionObject) result).getContextHolder());
}
public void testDoBegin() {
contextSourceControl.expectAndReturn(contextSourceMock
.getReadOnlyContext(), contextMock);
contextSourceControl.replay();
ContextSourceTransactionObject expectedTransactionObject = new ContextSourceTransactionObject(
null);
tested.doBegin(expectedTransactionObject, transactionDefinitionMock);
contextSourceControl.verify();
DirContextHolder foundContextHolder = (DirContextHolder) TransactionSynchronizationManager
.getResource(contextSourceMock);
assertSame(contextMock, foundContextHolder.getCtx());
assertSame(renamingStrategyMock, foundContextHolder
.getRenamingStrategy());
}
public void testDoCommit() {
}
public void testDoRollback() {
DirContextHolder expectedContextHolder = new DirContextHolder(
contextMock, renamingStrategyMock);
expectedContextHolder
.setTransactionDataManager(transactionDataManagerMock);
TransactionSynchronizationManager.bindResource(contextSourceMock,
expectedContextHolder);
transactionDataManagerMock.rollback();
transactionDataManagerControl.replay();
ContextSourceTransactionObject transactionObject = new ContextSourceTransactionObject(
null);
transactionObject.setContextHolder(expectedContextHolder);
tested.doRollback(new DefaultTransactionStatus(transactionObject,
false, false, false, false, null));
transactionDataManagerControl.verify();
}
public void testDoCleanupAfterCompletion() throws Exception {
DirContextHolder expectedContextHolder = new DirContextHolder(
contextMock, renamingStrategyMock);
TransactionSynchronizationManager.bindResource(contextSourceMock,
expectedContextHolder);
contextMock.close();
contextControl.replay();
tested.doCleanupAfterCompletion(new ContextSourceTransactionObject(
expectedContextHolder));
contextControl.verify();
assertNull(TransactionSynchronizationManager
.getResource(contextSourceMock));
assertNull(expectedContextHolder.getTransactionDataManager());
}
public void testSetContextSource_Proxy() {
TransactionAwareContextSourceProxy proxy = new TransactionAwareContextSourceProxy(
contextSourceMock);
// Perform test
tested.setContextSource(proxy);
ContextSource result = tested.getContextSource();
// Verify result
assertSame(contextSourceMock, result);
}
}

View File

@@ -1,34 +0,0 @@
package org.springframework.ldap.transaction.core;
import javax.naming.Name;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.transaction.core.DefaultTempEntryRenamingStrategy;
import junit.framework.TestCase;
public class DefaultTempEntryRenamingStrategyTest extends TestCase {
public void testGetTemporaryName() {
DistinguishedName expectedOriginalName = new DistinguishedName(
"cn=john doe, ou=somecompany, c=SE");
DefaultTempEntryRenamingStrategy tested = new DefaultTempEntryRenamingStrategy();
Name result = tested.getTemporaryName(expectedOriginalName);
assertEquals("cn=john doe_temp, ou=somecompany, c=SE", result
.toString());
assertNotSame(expectedOriginalName, result);
}
public void testGetTemporaryDN_MultivalueDN() {
DistinguishedName expectedOriginalName = new DistinguishedName(
"cn=john doe+sn=doe, ou=somecompany, c=SE");
DefaultTempEntryRenamingStrategy tested = new DefaultTempEntryRenamingStrategy();
Name result = tested.getTemporaryName(expectedOriginalName);
assertEquals("cn=john doe_temp+sn=doe, ou=somecompany, c=SE", result
.toString());
}
}

View File

@@ -1,28 +0,0 @@
package org.springframework.ldap.transaction.core;
import javax.naming.Name;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.transaction.core.DifferentSubtreeTempEntryRenamingStrategy;
import junit.framework.TestCase;
public class DifferentSubtreeTempEntryRenamingStrategyTest extends TestCase {
public void testGetTemporaryName() {
DistinguishedName originalName = new DistinguishedName(
"cn=john doe, ou=somecompany, c=SE");
DifferentSubtreeTempEntryRenamingStrategy tested = new DifferentSubtreeTempEntryRenamingStrategy(
new DistinguishedName("ou=tempEntries"));
int nextSequenceNo = tested.getNextSequenceNo();
// Perform test
Name result = tested.getTemporaryName(originalName);
// Verify result
assertEquals("cn=john doe" + nextSequenceNo + ", ou=tempEntries",
result.toString());
}
}

View File

@@ -1,120 +0,0 @@
package org.springframework.ldap.transaction.core;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.ldap.core.LdapOperations;
import org.springframework.ldap.transaction.CompensatingTransactionOperationRecorder;
import org.springframework.ldap.transaction.core.BindOperationRecorder;
import org.springframework.ldap.transaction.core.LdapCompensatingTransactionOperationFactory;
import org.springframework.ldap.transaction.core.ModifyAttributesOperationRecorder;
import org.springframework.ldap.transaction.core.RebindOperationRecorder;
import org.springframework.ldap.transaction.core.RenameOperationRecorder;
import org.springframework.ldap.transaction.core.TempEntryRenamingStrategy;
import org.springframework.ldap.transaction.core.UnbindOperationRecorder;
public class LdapCompensatingTransactionOperationFactoryTest extends TestCase {
private MockControl ldapOperationsControl;
private LdapOperations ldapOperationsMock;
private MockControl renamingStrategyControl;
private TempEntryRenamingStrategy renamingStrategyMock;
protected void setUp() throws Exception {
ldapOperationsControl = MockControl.createControl(LdapOperations.class);
ldapOperationsMock = (LdapOperations) ldapOperationsControl.getMock();
renamingStrategyControl = MockControl
.createControl(TempEntryRenamingStrategy.class);
renamingStrategyMock = (TempEntryRenamingStrategy) renamingStrategyControl
.getMock();
}
protected void tearDown() throws Exception {
ldapOperationsControl = null;
ldapOperationsMock = null;
renamingStrategyControl = null;
renamingStrategyMock = null;
}
protected void replay() {
ldapOperationsControl.replay();
renamingStrategyControl.replay();
}
protected void verify() {
ldapOperationsControl.verify();
renamingStrategyControl.verify();
}
public void testGetRecordingOperation_Bind() throws Exception {
LdapCompensatingTransactionOperationFactory tested = new LdapCompensatingTransactionOperationFactory(
null, renamingStrategyMock);
tested.setLdapOperations(ldapOperationsMock);
CompensatingTransactionOperationRecorder result = tested
.createRecordingOperation("bind");
assertTrue(result instanceof BindOperationRecorder);
BindOperationRecorder bindOperationRecorder = (BindOperationRecorder) result;
assertSame(ldapOperationsMock, bindOperationRecorder
.getLdapOperations());
}
public void testGetRecordingOperation_Rebind() throws Exception {
LdapCompensatingTransactionOperationFactory tested = new LdapCompensatingTransactionOperationFactory(
null, renamingStrategyMock);
tested.setLdapOperations(ldapOperationsMock);
CompensatingTransactionOperationRecorder result = tested
.createRecordingOperation("rebind");
assertTrue(result instanceof RebindOperationRecorder);
RebindOperationRecorder rebindOperationRecorder = (RebindOperationRecorder) result;
assertSame(ldapOperationsMock, rebindOperationRecorder
.getLdapOperations());
assertSame(renamingStrategyMock, rebindOperationRecorder
.getRenamingStrategy());
}
public void testGetRecordingOperation_Rename() throws Exception {
LdapCompensatingTransactionOperationFactory tested = new LdapCompensatingTransactionOperationFactory(
null, renamingStrategyMock);
tested.setLdapOperations(ldapOperationsMock);
CompensatingTransactionOperationRecorder result = tested
.createRecordingOperation("rename");
assertTrue(result instanceof RenameOperationRecorder);
RenameOperationRecorder recordingOperation = (RenameOperationRecorder) result;
assertSame(ldapOperationsMock, recordingOperation.getLdapOperations());
}
public void testGetRecordingOperation_ModifyAttributes() throws Exception {
LdapCompensatingTransactionOperationFactory tested = new LdapCompensatingTransactionOperationFactory(
null, renamingStrategyMock);
tested.setLdapOperations(ldapOperationsMock);
CompensatingTransactionOperationRecorder result = tested
.createRecordingOperation("modifyAttributes");
assertTrue(result instanceof ModifyAttributesOperationRecorder);
ModifyAttributesOperationRecorder recordingOperation = (ModifyAttributesOperationRecorder) result;
assertSame(ldapOperationsMock, recordingOperation.getLdapOperations());
}
public void testGetRecordingOperation_Unbind() throws Exception {
LdapCompensatingTransactionOperationFactory tested = new LdapCompensatingTransactionOperationFactory(
null, renamingStrategyMock);
tested.setLdapOperations(ldapOperationsMock);
CompensatingTransactionOperationRecorder result = tested
.createRecordingOperation("unbind");
assertTrue(result instanceof UnbindOperationRecorder);
UnbindOperationRecorder recordingOperation = (UnbindOperationRecorder) result;
assertSame(ldapOperationsMock, recordingOperation.getLdapOperations());
assertSame(renamingStrategyMock, recordingOperation
.getRenamingStrategy());
}
}

View File

@@ -1,94 +0,0 @@
package org.springframework.ldap.transaction.core;
import javax.naming.Name;
import javax.naming.directory.ModificationItem;
import org.easymock.MockControl;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.LdapOperations;
import org.springframework.ldap.transaction.core.ModifyAttributesOperationExecutor;
import junit.framework.TestCase;
public class ModifyAttributesOperationExecutorTest 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 testPerformOperation() {
ModificationItem[] expectedCompensatingItems = new ModificationItem[0];
ModificationItem[] expectedActualItems = new ModificationItem[0];
Name expectedDn = new DistinguishedName("cn=john doe");
ModifyAttributesOperationExecutor tested = new ModifyAttributesOperationExecutor(
ldapOperationsMock, expectedDn, expectedActualItems,
expectedCompensatingItems);
ldapOperationsMock.modifyAttributes(expectedDn, expectedActualItems);
replay();
// Perform test
tested.performOperation();
verify();
}
public void testCommit() {
ModificationItem[] expectedCompensatingItems = new ModificationItem[0];
ModificationItem[] expectedActualItems = new ModificationItem[0];
Name expectedDn = new DistinguishedName("cn=john doe");
ModifyAttributesOperationExecutor tested = new ModifyAttributesOperationExecutor(
ldapOperationsMock, expectedDn, expectedActualItems,
expectedCompensatingItems);
// No operation here
replay();
// Perform test
tested.commit();
verify();
}
public void testRollback() {
ModificationItem[] expectedCompensatingItems = new ModificationItem[0];
ModificationItem[] expectedActualItems = new ModificationItem[0];
Name expectedDn = new DistinguishedName("cn=john doe");
ModifyAttributesOperationExecutor tested = new ModifyAttributesOperationExecutor(
ldapOperationsMock, expectedDn, expectedActualItems,
expectedCompensatingItems);
ldapOperationsMock.modifyAttributes(expectedDn,
expectedCompensatingItems);
replay();
// Perform test
tested.rollback();
verify();
}
}

View File

@@ -1,256 +0,0 @@
package org.springframework.ldap.transaction.core;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.ModificationItem;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.LdapOperations;
import org.springframework.ldap.transaction.CompensatingTransactionOperationExecutor;
import org.springframework.ldap.transaction.core.ModifyAttributesOperationExecutor;
import org.springframework.ldap.transaction.core.ModifyAttributesOperationRecorder;
public class ModifyAttributesOperationRecorderTest extends TestCase {
private MockControl ldapOperationsControl;
private LdapOperations ldapOperationsMock;
private MockControl attributesMapperControl;
private AttributesMapper attributesMapperMock;
private ModifyAttributesOperationRecorder tested;
protected void setUp() throws Exception {
ldapOperationsControl = MockControl.createControl(LdapOperations.class);
ldapOperationsMock = (LdapOperations) ldapOperationsControl.getMock();
attributesMapperControl = MockControl
.createControl(AttributesMapper.class);
attributesMapperMock = (AttributesMapper) attributesMapperControl
.getMock();
tested = new ModifyAttributesOperationRecorder(ldapOperationsMock);
}
protected void tearDown() throws Exception {
ldapOperationsControl = null;
ldapOperationsMock = null;
attributesMapperControl = null;
attributesMapperMock = null;
tested = null;
}
protected void replay() {
ldapOperationsControl.replay();
attributesMapperControl.replay();
}
protected void verify() {
ldapOperationsControl.verify();
attributesMapperControl.verify();
}
public void testRecordOperation() {
final ModificationItem incomingItem = new ModificationItem(
DirContext.ADD_ATTRIBUTE, new BasicAttribute("attribute1"));
ModificationItem[] incomingMods = new ModificationItem[] { incomingItem };
final ModificationItem compensatingItem = new ModificationItem(
DirContext.ADD_ATTRIBUTE, new BasicAttribute("attribute2"));
final Attributes expectedAttributes = new BasicAttributes();
tested = new ModifyAttributesOperationRecorder(ldapOperationsMock) {
AttributesMapper getAttributesMapper() {
return attributesMapperMock;
}
protected ModificationItem getCompensatingModificationItem(
Attributes originalAttributes,
ModificationItem modificationItem) {
assertSame(expectedAttributes, originalAttributes);
assertSame(incomingItem, modificationItem);
return compensatingItem;
}
};
DistinguishedName expectedName = new DistinguishedName("cn=john doe");
ldapOperationsControl.setDefaultMatcher(MockControl.ARRAY_MATCHER);
ldapOperationsControl.expectAndReturn(ldapOperationsMock.lookup(
expectedName, new String[] { "attribute1" },
attributesMapperMock), expectedAttributes);
replay();
// Perform test
CompensatingTransactionOperationExecutor operation = tested
.recordOperation(new Object[] { expectedName, incomingMods });
verify();
// Verify outcome
assertTrue(operation instanceof ModifyAttributesOperationExecutor);
ModifyAttributesOperationExecutor rollbackOperation = (ModifyAttributesOperationExecutor) operation;
assertSame(expectedName, rollbackOperation.getDn());
assertSame(ldapOperationsMock, rollbackOperation.getLdapOperations());
assertSame(incomingMods, rollbackOperation.getActualModifications());
assertEquals(1, rollbackOperation.getCompensatingModifications().length);
assertSame(compensatingItem, rollbackOperation
.getCompensatingModifications()[0]);
}
public void testGetCompensatingModificationItem_RemoveFullExistingAttribute()
throws NamingException {
BasicAttribute attribute = new BasicAttribute("someattr");
attribute.add("value1");
attribute.add("value2");
Attributes attributes = new BasicAttributes();
attributes.put(attribute);
ModificationItem originalItem = new ModificationItem(
DirContext.REMOVE_ATTRIBUTE, new BasicAttribute("someattr"));
// Perform test
ModificationItem result = tested.getCompensatingModificationItem(
attributes, originalItem);
// Verify result
assertEquals(DirContext.ADD_ATTRIBUTE, result.getModificationOp());
Attribute resultAttribute = result.getAttribute();
assertEquals("someattr", resultAttribute.getID());
Object object = resultAttribute.get(0);
assertEquals("value1", object);
assertEquals("value2", resultAttribute.get(1));
}
public void testGetCompensatingModificationItem_RemoveTwoAttributeValues()
throws NamingException {
BasicAttribute attribute = new BasicAttribute("someattr");
attribute.add("value1");
attribute.add("value2");
attribute.add("value3");
Attributes attributes = new BasicAttributes();
attributes.put(attribute);
BasicAttribute modificationAttribute = new BasicAttribute("someattr");
modificationAttribute.add("value1");
modificationAttribute.add("value2");
ModificationItem originalItem = new ModificationItem(
DirContext.REMOVE_ATTRIBUTE, modificationAttribute);
// Perform test
ModificationItem result = tested.getCompensatingModificationItem(
attributes, originalItem);
// Verify result
assertEquals(DirContext.ADD_ATTRIBUTE, result.getModificationOp());
Attribute resultAttribute = result.getAttribute();
assertEquals("someattr", resultAttribute.getID());
Object object = resultAttribute.get(0);
assertEquals("value1", object);
assertEquals("value2", resultAttribute.get(1));
}
public void testGetCompensatingModificationItem_ReplaceExistingAttribute()
throws NamingException {
BasicAttribute attribute = new BasicAttribute("someattr");
attribute.add("value1");
attribute.add("value2");
Attributes attributes = new BasicAttributes();
attributes.put(attribute);
BasicAttribute modificationAttribute = new BasicAttribute("someattr");
modificationAttribute.add("newvalue1");
modificationAttribute.add("newvalue2");
ModificationItem originalItem = new ModificationItem(
DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("someattr"));
// Perform test
ModificationItem result = tested.getCompensatingModificationItem(
attributes, originalItem);
// Verify result
assertEquals(DirContext.REPLACE_ATTRIBUTE, result.getModificationOp());
Attribute resultAttribute = result.getAttribute();
assertEquals("someattr", resultAttribute.getID());
Object object = resultAttribute.get(0);
assertEquals("value1", object);
assertEquals("value2", resultAttribute.get(1));
}
public void testGetCompensatingModificationItem_ReplaceNonExistingAttribute()
throws NamingException {
Attributes attributes = new BasicAttributes();
BasicAttribute modificationAttribute = new BasicAttribute("someattr");
modificationAttribute.add("newvalue1");
modificationAttribute.add("newvalue2");
ModificationItem originalItem = new ModificationItem(
DirContext.REPLACE_ATTRIBUTE, modificationAttribute);
// Perform test
ModificationItem result = tested.getCompensatingModificationItem(
attributes, originalItem);
// Verify result
assertEquals(DirContext.REMOVE_ATTRIBUTE, result.getModificationOp());
Attribute resultAttribute = result.getAttribute();
assertEquals("someattr", resultAttribute.getID());
assertEquals(0, resultAttribute.size());
}
public void testGetCompensatingModificationItem_AddNonExistingAttribute()
throws NamingException {
Attributes attributes = new BasicAttributes();
BasicAttribute modificationAttribute = new BasicAttribute("someattr");
modificationAttribute.add("newvalue1");
modificationAttribute.add("newvalue2");
ModificationItem originalItem = new ModificationItem(
DirContext.ADD_ATTRIBUTE, modificationAttribute);
// Perform test
ModificationItem result = tested.getCompensatingModificationItem(
attributes, originalItem);
// Verify result
assertEquals(DirContext.REMOVE_ATTRIBUTE, result.getModificationOp());
Attribute resultAttribute = result.getAttribute();
assertEquals("someattr", resultAttribute.getID());
assertEquals(0, resultAttribute.size());
}
public void testGetCompensatingModificationItem_AddExistingAttribute()
throws NamingException {
BasicAttribute attribute = new BasicAttribute("someattr");
attribute.add("value1");
attribute.add("value2");
Attributes attributes = new BasicAttributes();
attributes.put(attribute);
BasicAttribute modificationAttribute = new BasicAttribute("someattr");
modificationAttribute.add("newvalue1");
modificationAttribute.add("newvalue2");
ModificationItem originalItem = new ModificationItem(
DirContext.ADD_ATTRIBUTE, new BasicAttribute("someattr"));
// Perform test
ModificationItem result = tested.getCompensatingModificationItem(
attributes, originalItem);
// Verify result
assertEquals(DirContext.REPLACE_ATTRIBUTE, result.getModificationOp());
Attribute resultAttribute = result.getAttribute();
assertEquals("someattr", resultAttribute.getID());
assertEquals("value1", result.getAttribute().get(0));
assertEquals("value2", result.getAttribute().get(1));
}
}

View File

@@ -1,95 +0,0 @@
package org.springframework.ldap.transaction.core;
import javax.naming.directory.BasicAttributes;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.LdapOperations;
import org.springframework.ldap.transaction.core.RebindOperationExecutor;
public class RebindOperationExecutorTest 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 testPerformOperation() {
DistinguishedName expectedOriginalDn = new DistinguishedName(
"cn=john doe");
DistinguishedName expectedTempDn = new DistinguishedName(
"cn=john doe_temp");
Object expectedObject = new Object();
BasicAttributes expectedAttributes = new BasicAttributes();
RebindOperationExecutor tested = new RebindOperationExecutor(
ldapOperationsMock, expectedOriginalDn, expectedTempDn,
expectedObject, expectedAttributes);
ldapOperationsMock.rename(expectedOriginalDn, expectedTempDn);
ldapOperationsMock.bind(expectedOriginalDn, expectedObject,
expectedAttributes);
replay();
// perform test
tested.performOperation();
verify();
}
public void testCommit() {
DistinguishedName expectedOriginalDn = new DistinguishedName(
"cn=john doe");
DistinguishedName expectedTempDn = new DistinguishedName(
"cn=john doe_temp");
Object expectedObject = new Object();
BasicAttributes expectedAttributes = new BasicAttributes();
RebindOperationExecutor tested = new RebindOperationExecutor(
ldapOperationsMock, expectedOriginalDn, expectedTempDn,
expectedObject, expectedAttributes);
ldapOperationsMock.unbind(expectedTempDn);
replay();
// perform test
tested.commit();
verify();
}
public void testRollback() {
DistinguishedName expectedOriginalDn = new DistinguishedName(
"cn=john doe");
DistinguishedName expectedTempDn = new DistinguishedName(
"cn=john doe_temp");
Object expectedObject = new Object();
BasicAttributes expectedAttributes = new BasicAttributes();
RebindOperationExecutor tested = new RebindOperationExecutor(
ldapOperationsMock, expectedOriginalDn, expectedTempDn,
expectedObject, expectedAttributes);
ldapOperationsMock.unbind(expectedOriginalDn);
ldapOperationsMock.rename(expectedTempDn, expectedOriginalDn);
replay();
// perform test
tested.rollback();
verify();
}
}

View File

@@ -1,84 +0,0 @@
package org.springframework.ldap.transaction.core;
import javax.naming.directory.BasicAttributes;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.LdapOperations;
import org.springframework.ldap.transaction.CompensatingTransactionOperationExecutor;
import org.springframework.ldap.transaction.core.RebindOperationExecutor;
import org.springframework.ldap.transaction.core.RebindOperationRecorder;
import org.springframework.ldap.transaction.core.TempEntryRenamingStrategy;
public class RebindOperationRecorderTest extends TestCase {
private MockControl ldapOperationsControl;
private LdapOperations ldapOperationsMock;
private MockControl renamingStrategyControl;
private TempEntryRenamingStrategy renamingStrategyMock;
protected void setUp() throws Exception {
ldapOperationsControl = MockControl.createControl(LdapOperations.class);
ldapOperationsMock = (LdapOperations) ldapOperationsControl.getMock();
renamingStrategyControl = MockControl
.createControl(TempEntryRenamingStrategy.class);
renamingStrategyMock = (TempEntryRenamingStrategy) renamingStrategyControl
.getMock();
}
protected void tearDown() throws Exception {
ldapOperationsControl = null;
ldapOperationsMock = null;
renamingStrategyControl = null;
renamingStrategyMock = null;
}
protected void replay() {
ldapOperationsControl.replay();
renamingStrategyControl.replay();
}
protected void verify() {
ldapOperationsControl.verify();
renamingStrategyControl.verify();
}
public void testRecordOperation() {
final DistinguishedName expectedDn = new DistinguishedName(
"cn=john doe");
final DistinguishedName expectedTempDn = new DistinguishedName(
"cn=john doe");
RebindOperationRecorder tested = new RebindOperationRecorder(
ldapOperationsMock, renamingStrategyMock);
renamingStrategyControl.expectAndReturn(renamingStrategyMock
.getTemporaryName(expectedDn), expectedTempDn);
replay();
Object expectedObject = new Object();
BasicAttributes expectedAttributes = new BasicAttributes();
// perform test
CompensatingTransactionOperationExecutor result = tested
.recordOperation(new Object[] { expectedDn, expectedObject,
expectedAttributes });
verify();
assertTrue(result instanceof RebindOperationExecutor);
RebindOperationExecutor rollbackOperation = (RebindOperationExecutor) result;
assertSame(ldapOperationsMock, rollbackOperation.getLdapOperations());
assertSame(expectedDn, rollbackOperation.getOriginalDn());
assertSame(expectedTempDn, rollbackOperation.getTemporaryDn());
assertSame(expectedObject, rollbackOperation.getOriginalObject());
assertSame(expectedAttributes, rollbackOperation
.getOriginalAttributes());
}
}

View File

@@ -1,75 +0,0 @@
package org.springframework.ldap.transaction.core;
import org.easymock.MockControl;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.LdapOperations;
import org.springframework.ldap.transaction.core.RenameOperationExecutor;
import junit.framework.TestCase;
public class RenameOperationExecutorTest 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 testPerformOperation() {
DistinguishedName expectedNewName = new DistinguishedName("ou=newOu");
DistinguishedName expectedOldName = new DistinguishedName("ou=someou");
RenameOperationExecutor tested = new RenameOperationExecutor(
ldapOperationsMock, expectedOldName, expectedNewName);
ldapOperationsMock.rename(expectedOldName, expectedNewName);
replay();
// Perform test.
tested.performOperation();
verify();
}
public void testCommit() {
DistinguishedName expectedNewName = new DistinguishedName("ou=newOu");
DistinguishedName expectedOldName = new DistinguishedName("ou=someou");
RenameOperationExecutor tested = new RenameOperationExecutor(
ldapOperationsMock, expectedOldName, expectedNewName);
// Nothing to do for this operation.
replay();
// Perform test.
tested.commit();
verify();
}
public void testRollback() {
DistinguishedName expectedNewName = new DistinguishedName("ou=newOu");
DistinguishedName expectedOldName = new DistinguishedName("ou=someou");
RenameOperationExecutor tested = new RenameOperationExecutor(
ldapOperationsMock, expectedOldName, expectedNewName);
ldapOperationsMock.rename(expectedNewName, expectedOldName);
replay();
// Perform test.
tested.rollback();
verify();
}
}

View File

@@ -1,52 +0,0 @@
package org.springframework.ldap.transaction.core;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.ldap.core.LdapOperations;
import org.springframework.ldap.transaction.CompensatingTransactionOperationExecutor;
import org.springframework.ldap.transaction.core.RenameOperationExecutor;
import org.springframework.ldap.transaction.core.RenameOperationRecorder;
public class RenameOperationRecorderTest 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 testRecordOperation() {
RenameOperationRecorder tested = new RenameOperationRecorder(
ldapOperationsMock);
replay();
// Perform test
CompensatingTransactionOperationExecutor operation = tested
.recordOperation(new Object[] { "ou=someou", "ou=newou" });
verify();
assertTrue(operation instanceof RenameOperationExecutor);
RenameOperationExecutor rollbackOperation = (RenameOperationExecutor) operation;
assertSame(ldapOperationsMock, rollbackOperation.getLdapOperations());
assertEquals("ou=newou", rollbackOperation.getNewDn().toString());
assertEquals("ou=someou", rollbackOperation.getOriginalDn().toString());
}
}

View File

@@ -1,76 +0,0 @@
package org.springframework.ldap.transaction.core;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.LdapOperations;
import org.springframework.ldap.transaction.core.UnbindOperationExecutor;
public class UnbindOperationExecutorTest 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 testPerformOperation() {
DistinguishedName expectedOldName = new DistinguishedName("cn=oldDn");
DistinguishedName expectedTempName = new DistinguishedName("cn=newDn");
UnbindOperationExecutor tested = new UnbindOperationExecutor(
ldapOperationsMock, expectedOldName, expectedTempName);
ldapOperationsMock.rename(expectedOldName, expectedTempName);
replay();
// Perform test
tested.performOperation();
verify();
}
public void testCommit() {
DistinguishedName expectedOldName = new DistinguishedName("cn=oldDn");
DistinguishedName expectedTempName = new DistinguishedName("cn=newDn");
UnbindOperationExecutor tested = new UnbindOperationExecutor(
ldapOperationsMock, expectedOldName, expectedTempName);
ldapOperationsMock.unbind(expectedTempName);
replay();
// Perform test
tested.commit();
verify();
}
public void testRollback() {
DistinguishedName expectedOldName = new DistinguishedName("cn=oldDn");
DistinguishedName expectedTempName = new DistinguishedName("cn=newDn");
UnbindOperationExecutor tested = new UnbindOperationExecutor(
ldapOperationsMock, expectedOldName, expectedTempName);
ldapOperationsMock.rename(expectedTempName, expectedOldName);
replay();
// Perform test
tested.rollback();
verify();
}
}

View File

@@ -1,77 +0,0 @@
package org.springframework.ldap.transaction.core;
import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.LdapOperations;
import org.springframework.ldap.transaction.CompensatingTransactionOperationExecutor;
import org.springframework.ldap.transaction.core.TempEntryRenamingStrategy;
import org.springframework.ldap.transaction.core.UnbindOperationExecutor;
import org.springframework.ldap.transaction.core.UnbindOperationRecorder;
public class UnbindOperationRecorderTest extends TestCase {
private MockControl ldapOperationsControl;
private LdapOperations ldapOperationsMock;
private MockControl renamingStrategyControl;
private TempEntryRenamingStrategy renamingStrategyMock;
protected void setUp() throws Exception {
ldapOperationsControl = MockControl.createControl(LdapOperations.class);
ldapOperationsMock = (LdapOperations) ldapOperationsControl.getMock();
renamingStrategyControl = MockControl
.createControl(TempEntryRenamingStrategy.class);
renamingStrategyMock = (TempEntryRenamingStrategy) renamingStrategyControl
.getMock();
}
protected void tearDown() throws Exception {
ldapOperationsControl = null;
ldapOperationsMock = null;
renamingStrategyControl = null;
renamingStrategyMock = null;
}
protected void replay() {
ldapOperationsControl.replay();
renamingStrategyControl.replay();
}
protected void verify() {
ldapOperationsControl.verify();
renamingStrategyControl.verify();
}
public void testRecordOperation() {
final DistinguishedName expectedTempName = new DistinguishedName(
"cn=john doe_temp");
final DistinguishedName expectedDn = new DistinguishedName(
"cn=john doe");
UnbindOperationRecorder tested = new UnbindOperationRecorder(
ldapOperationsMock, renamingStrategyMock);
renamingStrategyControl.expectAndReturn(renamingStrategyMock
.getTemporaryName(expectedDn), expectedTempName);
replay();
// Perform test
CompensatingTransactionOperationExecutor operation = tested
.recordOperation(new Object[] { expectedDn });
verify();
// Verify result
assertTrue(operation instanceof UnbindOperationExecutor);
UnbindOperationExecutor rollbackOperation = (UnbindOperationExecutor) operation;
assertSame(ldapOperationsMock, rollbackOperation.getLdapOperations());
assertSame(expectedDn, rollbackOperation.getOriginalDn());
assertSame(expectedTempName, rollbackOperation.getTemporaryDn());
}
}