Interation tests of bind and rebind operations, along with bugfixes for found problems.
This commit is contained in:
@@ -43,6 +43,10 @@
|
||||
<classpathentry kind="lib" path="lib/test/junit-addons.jar"/>
|
||||
<classpathentry kind="lib" path="lib/test/DDSteps.jar"/>
|
||||
<classpathentry kind="lib" path="lib/global/ldapbp.jar"/>
|
||||
<classpathentry kind="lib" path="lib/buildtime/spring-jdbc.jar" sourcepath="lib/source/spring-src.zip"/>
|
||||
<classpathentry kind="lib" path="lib/buildtime/spring-jpa.jar" sourcepath="lib/source/spring-src.zip"/>
|
||||
<classpathentry kind="lib" path="lib/test/spring-aop.jar" sourcepath="lib/source/spring-src.zip"/>
|
||||
<classpathentry kind="lib" path="lib/test/aopalliance.jar"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/spring-ldap"/>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beansProjectDescription>
|
||||
<configExtensions>
|
||||
<configExtension>xml</configExtension>
|
||||
</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>
|
||||
@@ -21,5 +25,13 @@
|
||||
<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>
|
||||
|
||||
@@ -43,6 +43,8 @@
|
||||
conf="buildtime->default" />
|
||||
<dependency org="org.springframework" name="spring-support" rev="2.0"
|
||||
conf="buildtime->default" />
|
||||
<dependency org="org.springframework" name="spring-jpa" rev="2.0"
|
||||
conf="buildtime->default" />
|
||||
|
||||
<!-- test time only dependencies -->
|
||||
<dependency org="com.cenqua.clover" name="clover" rev="1.3.12" conf="test->default" />
|
||||
@@ -57,6 +59,8 @@
|
||||
<dependency org="jexcelapi" name="jxl" rev="2.5.9" conf="test->default" />
|
||||
<dependency org="org.ddsteps" name="DDSteps" rev="1.1" conf="test->default" />
|
||||
<dependency org="cglib" name="cglib-nodep" rev="2.1_3" conf="test->default"/>
|
||||
<dependency org="org.springframework" name="spring-aop" rev="2.0" conf="test->default"/>
|
||||
<dependency org="aopalliance" name="aopalliance" rev="1.0" conf="test->default" />
|
||||
|
||||
<!-- Test dependencies for Apache Directory Server -->
|
||||
<dependency org="org.apache.directory.server" name="apacheds-core" rev="1.0-RC3"
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
|
||||
<beans>
|
||||
<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.support.LdapContextSource">
|
||||
<property name="urls" value="${urls}" />
|
||||
<property name="userName" value="${userName}" />
|
||||
<property name="password" value="${password}" />
|
||||
<property name="base" value="${base}" />
|
||||
<property name="pooled" value="false" />
|
||||
<property name="dirObjectFactory"
|
||||
value="org.springframework.ldap.support.DefaultDirObjectFactory" />
|
||||
</bean>
|
||||
|
||||
<bean id="contextSource"
|
||||
class="org.springframework.ldap.support.transaction.TransactionAwareContextSourceProxy">
|
||||
<constructor-arg ref="contextSourceTarget" />
|
||||
</bean>
|
||||
|
||||
<bean id="ldapTemplate"
|
||||
class="org.springframework.ldap.LdapTemplate">
|
||||
<constructor-arg ref="contextSource" />
|
||||
</bean>
|
||||
|
||||
<bean id="transactionManager"
|
||||
class="org.springframework.ldap.support.transaction.ContextSourceTransactionManager">
|
||||
<property name="contextSource" ref="contextSourceTarget" />
|
||||
</bean>
|
||||
|
||||
<bean name="dummyDaoTarget"
|
||||
class="org.springframework.ldap.support.transaction.DummyDaoImpl">
|
||||
<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_REQUIRED</prop>
|
||||
</props>
|
||||
</property>
|
||||
</bean>
|
||||
</beans>
|
||||
@@ -5,5 +5,4 @@ log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n
|
||||
|
||||
#Enable debug logging
|
||||
log4j.category.net.sf.ldaptemplate=INFO
|
||||
log4j.category.net.sf.ldaptemplate.LdapTemplate=DEBUG
|
||||
log4j.category.org.springframework.ldap=DEBUG
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2002-2005 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;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import javax.naming.Context;
|
||||
|
||||
import org.apache.directory.server.configuration.MutableServerStartupConfiguration;
|
||||
import org.apache.directory.server.jndi.ServerContextFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
/**
|
||||
* Helper class to simplify Spring configuration of ApacheDS.
|
||||
*
|
||||
* @author Mattias Arthursson
|
||||
*/
|
||||
public class ConfigEnvHelper implements InitializingBean {
|
||||
private final MutableServerStartupConfiguration configuration;
|
||||
|
||||
private final Hashtable initialEnv;
|
||||
|
||||
private final File workingDir = new File(System
|
||||
.getProperty("java.io.tmpdir")
|
||||
+ File.separator + "ldaptemplate_apacheds");
|
||||
|
||||
public ConfigEnvHelper(Hashtable initialEnv,
|
||||
MutableServerStartupConfiguration configuration) {
|
||||
|
||||
this.initialEnv = initialEnv;
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
public Hashtable getEnv() {
|
||||
return initialEnv;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
initialEnv.put(Context.INITIAL_CONTEXT_FACTORY, ServerContextFactory.class.getName());
|
||||
configuration.setWorkingDirectory(workingDir);
|
||||
initialEnv.putAll(configuration.toJndiEnvironment());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright 2002-2005 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;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.naming.Binding;
|
||||
import javax.naming.Context;
|
||||
import javax.naming.ContextNotEmptyException;
|
||||
import javax.naming.InitialContext;
|
||||
import javax.naming.Name;
|
||||
import javax.naming.NamingEnumeration;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.DirContext;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.directory.server.core.configuration.ShutdownConfiguration;
|
||||
import org.apache.directory.server.jndi.ServerContextFactory;
|
||||
import org.apache.directory.server.protocol.shared.store.LdifFileLoader;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.ldap.support.DefaultDirObjectFactory;
|
||||
import org.springframework.ldap.support.DistinguishedName;
|
||||
|
||||
/**
|
||||
* Utility class to initialize the apache directory server for use in the
|
||||
* integration tests.
|
||||
*
|
||||
* @author Mattias Arthursson
|
||||
*
|
||||
*/
|
||||
public class LdapServerManager implements DisposableBean {
|
||||
private static Log log = LogFactory.getLog(LdapServerManager.class);
|
||||
|
||||
private ContextSource contextSource;
|
||||
|
||||
public void setContextSource(ContextSource contextSource) {
|
||||
this.contextSource = contextSource;
|
||||
}
|
||||
|
||||
public void destroy() throws Exception {
|
||||
Properties env = new Properties();
|
||||
env.setProperty(Context.INITIAL_CONTEXT_FACTORY,
|
||||
ServerContextFactory.class.getName());
|
||||
env.setProperty(Context.SECURITY_AUTHENTICATION, "simple");
|
||||
env.setProperty(Context.SECURITY_PRINCIPAL, "uid=admin,ou=system");
|
||||
env.setProperty(Context.SECURITY_CREDENTIALS, "secret");
|
||||
|
||||
ShutdownConfiguration configuration = new ShutdownConfiguration();
|
||||
env.putAll(configuration.toJndiEnvironment());
|
||||
|
||||
new InitialContext(env);
|
||||
}
|
||||
|
||||
public void cleanAndSetup(String ldifFile) throws Exception {
|
||||
DirContext ctx = contextSource.getReadWriteContext();
|
||||
|
||||
// First of all, make sure the database is empty.
|
||||
Name startingPoint = null;
|
||||
|
||||
// Different test cases have different base paths. This means that the
|
||||
// starting point will be different.
|
||||
if (ctx.getEnvironment().get(
|
||||
DefaultDirObjectFactory.JNDI_ENV_BASE_PATH_KEY) != null) {
|
||||
startingPoint = DistinguishedName.EMPTY_PATH;
|
||||
} else {
|
||||
startingPoint = new DistinguishedName("dc=jayway,dc=se");
|
||||
}
|
||||
|
||||
try {
|
||||
log.info("Cleaning all present data.");
|
||||
clearSubContexts(ctx, startingPoint);
|
||||
// Load the ldif to the recently started server
|
||||
log.info("Loading setup data");
|
||||
LdifFileLoader loader = new LdifFileLoader(ctx, ldifFile);
|
||||
loader.execute();
|
||||
} finally {
|
||||
ctx.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void clearSubContexts(DirContext ctx, Name name)
|
||||
throws NamingException {
|
||||
|
||||
NamingEnumeration enumeration = null;
|
||||
try {
|
||||
enumeration = ctx.listBindings(name);
|
||||
while (enumeration.hasMore()) {
|
||||
Binding element = (Binding) enumeration.next();
|
||||
DistinguishedName childName = new DistinguishedName(element
|
||||
.getName());
|
||||
childName.prepend((DistinguishedName) name);
|
||||
|
||||
try {
|
||||
ctx.destroySubcontext(childName);
|
||||
} catch (ContextNotEmptyException e) {
|
||||
clearSubContexts(ctx, childName);
|
||||
ctx.destroySubcontext(childName);
|
||||
}
|
||||
}
|
||||
} catch (NamingException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
enumeration.close();
|
||||
} catch (Exception e) {
|
||||
// Never mind this
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package org.springframework.ldap.support.transaction;
|
||||
|
||||
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.AttributesMapper;
|
||||
import org.springframework.ldap.EntryNotFoundException;
|
||||
import org.springframework.ldap.LdapServerManager;
|
||||
import org.springframework.ldap.LdapTemplate;
|
||||
import org.springframework.test.AbstractDependencyInjectionSpringContextTests;
|
||||
|
||||
public class ContextSourceTransactionManagerIntegrationTest extends
|
||||
AbstractDependencyInjectionSpringContextTests {
|
||||
|
||||
private static Log log = LogFactory
|
||||
.getLog(ContextSourceTransactionManagerIntegrationTest.class);
|
||||
|
||||
public ContextSourceTransactionManagerIntegrationTest() {
|
||||
setAutowireMode(AbstractDependencyInjectionSpringContextTests.AUTOWIRE_BY_NAME);
|
||||
}
|
||||
|
||||
private DummyDaoImpl 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(DummyDaoImpl dummyDaoImpl) {
|
||||
this.dummyDao = dummyDaoImpl;
|
||||
}
|
||||
|
||||
protected String[] getConfigLocations() {
|
||||
return new String[] { "conf/ldapTemplateTransactionTestContext.xml" };
|
||||
}
|
||||
|
||||
protected void onSetUp() throws Exception {
|
||||
ldapServerManager.cleanAndSetup("setup_data.ldif");
|
||||
}
|
||||
|
||||
public void testCreateWithException() {
|
||||
try {
|
||||
dummyDao.createWithException("Sweden", "company1",
|
||||
"some testperson", "testperson", "some description");
|
||||
fail("RuntimeException expected");
|
||||
} catch (RuntimeException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
log.debug("Verifying result");
|
||||
|
||||
try {
|
||||
ldapTemplate.lookup("cn=some testperson, ou=company1, c=Sweden");
|
||||
fail("EntryNotFoundException expected");
|
||||
} catch (EntryNotFoundException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testCreateWithNoException() {
|
||||
dummyDao.create("Sweden", "company1", "some testperson", "testperson",
|
||||
"some description");
|
||||
|
||||
log.debug("Verifying result");
|
||||
ldapTemplate.lookup("cn=some testperson, ou=company1, c=Sweden");
|
||||
}
|
||||
|
||||
public void testUpdateWithException() {
|
||||
String dn = "cn=Some Person,ou=company1,c=Sweden";
|
||||
try {
|
||||
dummyDao.updateWithException(dn, "Updated Person",
|
||||
"Updated description");
|
||||
fail("RuntimeException expected");
|
||||
} catch (RuntimeException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
log.debug("Verifying result");
|
||||
|
||||
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 testUpdate() {
|
||||
String dn = "cn=Some Person,ou=company1,c=Sweden";
|
||||
dummyDao.update(dn, "Updated Person", "Updated description");
|
||||
|
||||
log.debug("Verifying result");
|
||||
Object result = 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(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package org.springframework.ldap.support.transaction;
|
||||
|
||||
public interface DummyDao {
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package org.springframework.ldap.support.transaction;
|
||||
|
||||
import org.springframework.ldap.LdapTemplate;
|
||||
import org.springframework.ldap.support.DirContextAdapter;
|
||||
import org.springframework.ldap.support.DistinguishedName;
|
||||
|
||||
public class DummyDaoImpl {
|
||||
private LdapTemplate ldapTemplate;
|
||||
|
||||
public void setLdapTemplate(LdapTemplate ldapTemplate) {
|
||||
this.ldapTemplate = ldapTemplate;
|
||||
}
|
||||
|
||||
public void createWithException(String country, String company,
|
||||
String fullname, String lastname, String description) {
|
||||
create(country, company, fullname, lastname, description);
|
||||
throw new RuntimeException("This method failed");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public void update(String dn, 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);
|
||||
}
|
||||
|
||||
public void updateWithException(String dn, String lastname,
|
||||
String description) {
|
||||
update(dn, lastname, description);
|
||||
throw new RuntimeException("This method failed.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.springframework.ldap.support.transaction;
|
||||
|
||||
public class DummyServiceImpl {
|
||||
private DummyDaoImpl dummyDaoImpl;
|
||||
|
||||
public void setDummyDaoImpl(DummyDaoImpl dummyDaoImpl) {
|
||||
this.dummyDaoImpl = dummyDaoImpl;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package org.springframework.ldap.support.transaction;
|
||||
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.ContextSource;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.TransactionException;
|
||||
@@ -20,6 +22,9 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
|
||||
public class ContextSourceTransactionManager extends
|
||||
AbstractPlatformTransactionManager {
|
||||
|
||||
private static Log log = LogFactory
|
||||
.getLog(ContextSourceTransactionManager.class);
|
||||
|
||||
private ContextSource contextSource;
|
||||
|
||||
/**
|
||||
@@ -98,11 +103,14 @@ public class ContextSourceTransactionManager extends
|
||||
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#doCleanupAfterCompletion(java.lang.Object)
|
||||
*/
|
||||
protected void doCleanupAfterCompletion(Object transaction) {
|
||||
ContextSourceTransactionObject txObject = (ContextSourceTransactionObject) 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();
|
||||
@@ -110,5 +118,4 @@ public class ContextSourceTransactionManager extends
|
||||
|
||||
txObject.getContextHolder().clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,6 @@ package org.springframework.ldap.support.transaction;
|
||||
|
||||
import javax.naming.directory.DirContext;
|
||||
|
||||
public interface DirContextProxy {
|
||||
public interface DirContextProxy extends DirContext {
|
||||
DirContext getTargetContext();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package org.springframework.ldap.support.transaction;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Stack;
|
||||
|
||||
import javax.naming.directory.DirContext;
|
||||
@@ -42,6 +46,7 @@ public class LdapCompensatingTransactionDataManager implements
|
||||
* @see org.springframework.ldap.support.CompensatingTransactionDataManager#rollback()
|
||||
*/
|
||||
public void rollback() {
|
||||
log.debug("Performing rollback");
|
||||
while (!rollbackOperations.isEmpty()) {
|
||||
CompensatingTransactionRollbackOperation rollbackOperation = (CompensatingTransactionRollbackOperation) rollbackOperations
|
||||
.pop();
|
||||
@@ -83,23 +88,6 @@ public class LdapCompensatingTransactionDataManager implements
|
||||
return new NullRecordingOperation();
|
||||
}
|
||||
|
||||
static class SingleContextSource implements ContextSource {
|
||||
private DirContext ctx;
|
||||
|
||||
public SingleContextSource(DirContext ctx) {
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
public DirContext getReadOnlyContext() throws DataAccessException {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
public DirContext getReadWriteContext() throws DataAccessException {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the LdapOperations to use. For testing purposes only.
|
||||
*
|
||||
@@ -110,4 +98,61 @@ public class LdapCompensatingTransactionDataManager implements
|
||||
this.ldapOperations = ldapOperations;
|
||||
}
|
||||
|
||||
static class SingleContextSource implements ContextSource {
|
||||
private DirContext ctx;
|
||||
|
||||
public SingleContextSource(DirContext ctx) {
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
public DirContext getReadOnlyContext() throws DataAccessException {
|
||||
return getNonClosingDirContextProxy(ctx);
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static class NonClosingDirContextInvocationHandler implements
|
||||
InvocationHandler {
|
||||
|
||||
private DirContext target;
|
||||
|
||||
public NonClosingDirContextInvocationHandler(DirContext target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ 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.ContextSource;
|
||||
import org.springframework.ldap.support.DistinguishedName;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
@@ -16,6 +18,8 @@ import org.springframework.util.Assert;
|
||||
* @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";
|
||||
@@ -63,9 +67,12 @@ public class LdapUtils {
|
||||
.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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,21 +17,7 @@ public class TransactionAwareContextSourceProxy implements ContextSource {
|
||||
}
|
||||
|
||||
public DirContext getReadOnlyContext() throws DataAccessException {
|
||||
DirContextHolder contextHolder = (DirContextHolder) TransactionSynchronizationManager
|
||||
.getResource(target);
|
||||
DirContext ctx = null;
|
||||
|
||||
if (contextHolder != null) {
|
||||
ctx = contextHolder.getCtx();
|
||||
}
|
||||
|
||||
if (ctx == null) {
|
||||
ctx = target.getReadOnlyContext();
|
||||
if (contextHolder != null) {
|
||||
contextHolder.setCtx(ctx);
|
||||
}
|
||||
}
|
||||
return getTransactionAwareDirContextProxy(ctx, target);
|
||||
return getReadWriteContext();
|
||||
}
|
||||
|
||||
private DirContext getTransactionAwareDirContextProxy(DirContext context,
|
||||
@@ -45,6 +31,20 @@ public class TransactionAwareContextSourceProxy implements ContextSource {
|
||||
}
|
||||
|
||||
public DirContext getReadWriteContext() throws DataAccessException {
|
||||
throw new UnsupportedOperationException("Not implemented yet");
|
||||
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,6 +1,3 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.springframework.ldap.support.transaction;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
@@ -45,7 +42,8 @@ public class TransactionAwareDirContextInvocationHandler implements
|
||||
return null;
|
||||
} else if (LdapUtils.isSupportedWriteTransactionOperation(methodName)) {
|
||||
// Store transaction data and allow operation to proceed.
|
||||
LdapUtils.storeCompensatingTransactionData(contextSource, methodName, args);
|
||||
LdapUtils.storeCompensatingTransactionData(contextSource,
|
||||
methodName, args);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -54,5 +52,4 @@ public class TransactionAwareDirContextInvocationHandler implements
|
||||
throw e.getTargetException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user