LDAP-29: Implement transaction support for Spring LDAP.
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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.");
|
||||
}
|
||||
}
|
||||
@@ -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.");
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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, "_temp".
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 "1" 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user