diff --git a/core/src/main/java/org/springframework/ldap/core/LdapOperations.java b/core/src/main/java/org/springframework/ldap/core/LdapOperations.java index 43d993a5..d9a3d9dc 100644 --- a/core/src/main/java/org/springframework/ldap/core/LdapOperations.java +++ b/core/src/main/java/org/springframework/ldap/core/LdapOperations.java @@ -26,7 +26,6 @@ import javax.naming.directory.ModificationItem; import javax.naming.directory.SearchControls; import org.springframework.dao.IncorrectResultSizeDataAccessException; -import org.springframework.ldap.AuthenticationException; import org.springframework.ldap.ContextNotEmptyException; import org.springframework.ldap.NamingException; import org.springframework.ldap.core.support.AbstractContextSource; @@ -1261,7 +1260,7 @@ public interface LdapOperations { /** * Bind the data in the supplied context in the tree. All specified - * Attributes in will be bound to the DN set on the instance. + * attributes ctxin will be bound to the DN set on ctx. *

* Example:
* @@ -1280,6 +1279,29 @@ public interface LdapOperations { */ void bind(DirContextOperations ctx); + /** + * Remove an entry and replace it with a new one. The attributes used to + * create the entry are retrieved from the ctx parameter. This + * method assumes that the specified context already exists - if not it will + * fail. The entry will be bound to the DN set on ctx. + *

+ * Example:
+ * + *

+	 * DirContextOperations ctx = new DirContextAdapter(dn);
+	 * ctx.setAttributeValue("cn", "john doe");
+	 * ctx.setAttributeValue("description", "some description");
+	 * //More initialization here.
+	 * 
+	 * ldapTemplate.rebind(ctx);
+	 * 
+ * @param ctx the context to rebind + * @throws IllegalStateException if no DN is set or if the instance is in + * update mode. + * @since 1.3 + */ + void rebind(DirContextOperations ctx); + /** * Utility method to perform a simple LDAP 'bind' authentication. Search for * the LDAP entry to authenticate using the supplied base DN and filter; use diff --git a/core/src/main/java/org/springframework/ldap/core/LdapTemplate.java b/core/src/main/java/org/springframework/ldap/core/LdapTemplate.java index 55fae4ad..6111e5b2 100644 --- a/core/src/main/java/org/springframework/ldap/core/LdapTemplate.java +++ b/core/src/main/java/org/springframework/ldap/core/LdapTemplate.java @@ -1337,7 +1337,7 @@ public class LdapTemplate implements LdapOperations, InitializingBean { /* * (non-Javadoc) * - * @seeorg.springframework.ldap.core.simple.SimpleLdapOperations#bind(org. + * @seeorg.springframework.ldap.core.LdapOperations#bind(org. * springframework.ldap.core.DirContextOperations) */ public void bind(DirContextOperations ctx) { @@ -1350,6 +1350,23 @@ public class LdapTemplate implements LdapOperations, InitializingBean { } } + + /* + * @see + * org.springframework.ldap.core.LdapOperations#rebind(org.springframework. + * ldap.core.DirContextOperations) + */ + public void rebind(DirContextOperations ctx) { + Name dn = ctx.getDn(); + if (dn != null && !ctx.isUpdateMode()) { + rebind(dn, ctx, null); + } + else { + throw new IllegalStateException( + "The DirContextOperations instance needs to be properly initialized."); + } + } + /* * (non-Javadoc) * diff --git a/core/src/test/java/org/springframework/ldap/core/LdapTemplateTest.java b/core/src/test/java/org/springframework/ldap/core/LdapTemplateTest.java index 3d7570f7..ad464b82 100644 --- a/core/src/test/java/org/springframework/ldap/core/LdapTemplateTest.java +++ b/core/src/test/java/org/springframework/ldap/core/LdapTemplateTest.java @@ -39,6 +39,12 @@ import org.springframework.ldap.NameNotFoundException; import org.springframework.ldap.PartialResultException; import org.springframework.ldap.UncategorizedLdapException; +/** + * Unit tests for the LdapTemplate class. + * + * @author Mattias Hellborg Arthursson + * @author Ulrik Sandberg + */ public class LdapTemplateTest extends TestCase { private static final String DEFAULT_BASE_STRING = "o=example.com"; @@ -168,7 +174,6 @@ public class LdapTemplateTest extends TestCase { dirContextOperationsConrol = null; dirContextOperationsMock = null; - } protected void replay() { @@ -1118,7 +1123,6 @@ public class LdapTemplateTest extends TestCase { tested.bind(nameMock, expectedObject, expectedAttributes); verify(); - } public void testBind_String() throws Exception { @@ -1134,7 +1138,6 @@ public class LdapTemplateTest extends TestCase { tested.bind(DEFAULT_BASE_STRING, expectedObject, expectedAttributes); verify(); - } public void testBind_NamingException() throws Exception { @@ -1158,7 +1161,23 @@ public class LdapTemplateTest extends TestCase { } verify(); + } + + public void testBindWithContext() throws Exception { + expectGetReadWriteContext(); + dirContextOperationsConrol.expectAndReturn(dirContextOperationsMock + .getDn(), nameMock); + dirContextOperationsConrol.expectAndReturn(dirContextOperationsMock + .isUpdateMode(), false); + dirContextMock.bind(nameMock, dirContextOperationsMock, null); + dirContextMock.close(); + + replay(); + + tested.bind(dirContextOperationsMock); + + verify(); } public void testUnbind() throws Exception { @@ -1184,6 +1203,23 @@ public class LdapTemplateTest extends TestCase { verify(); } + + public void testRebindWithContext() throws Exception { + expectGetReadWriteContext(); + + dirContextOperationsConrol.expectAndReturn(dirContextOperationsMock + .getDn(), nameMock); + dirContextOperationsConrol.expectAndReturn(dirContextOperationsMock + .isUpdateMode(), false); + dirContextMock.rebind(nameMock, dirContextOperationsMock, null); + dirContextMock.close(); + + replay(); + + tested.rebind(dirContextOperationsMock); + + verify(); + } public void testUnbindRecursive() throws Exception { expectGetReadWriteContext(); @@ -1864,16 +1900,17 @@ public class LdapTemplateTest extends TestCase { assertFalse(result); } + /** * Needed to verify search control values. * * @author Mattias Hellborg Arthursson */ private static class SearchControlsMatcher extends AbstractMatcher { - protected boolean argumentMatches(Object arg0, Object arg1) { - if (arg0 instanceof SearchControls && arg1 instanceof SearchControls) { - SearchControls s0 = (SearchControls) arg0; - SearchControls s1 = (SearchControls) arg1; + protected boolean argumentMatches(Object expected, Object actual) { + if (expected instanceof SearchControls && actual instanceof SearchControls) { + SearchControls s0 = (SearchControls) expected; + SearchControls s1 = (SearchControls) actual; return s0.getSearchScope() == s1.getSearchScope() && s0.getReturningObjFlag() == s1.getReturningObjFlag() @@ -1882,7 +1919,7 @@ public class LdapTemplateTest extends TestCase { && s0.getReturningAttributes() == s1.getReturningAttributes(); } else { - return super.argumentMatches(arg0, arg1); + return super.argumentMatches(expected, actual); } } } diff --git a/test/integration-tests/src/test/java/org/springframework/ldap/LdapTemplateBindUnbindITest.java b/test/integration-tests/src/test/java/org/springframework/ldap/LdapTemplateBindUnbindITest.java index b242e659..2eb56b62 100644 --- a/test/integration-tests/src/test/java/org/springframework/ldap/LdapTemplateBindUnbindITest.java +++ b/test/integration-tests/src/test/java/org/springframework/ldap/LdapTemplateBindUnbindITest.java @@ -36,21 +36,20 @@ import org.springframework.test.context.ContextConfiguration; * class tests a little too much, but we need to clean up after binding, so the * most efficient way to test is to do it all in one test method. Also, the * methods in this class relies on that the lookup method works as it should - - * that should be ok, since that is verified in a separate test class. NOTE: if - * any of the tests in this class fails, it may be necessary to run the cleanup - * script as described in README.txt under /src/iutest/. + * that should be ok, since that is verified in a separate test class. * * @author Mattias Hellborg Arthursson */ @ContextConfiguration(locations = { "/conf/ldapTemplateTestContext.xml" }) -public class LdapTemplateBindUnbindITest extends AbstractLdapTemplateIntegrationTest { +public class LdapTemplateBindUnbindITest extends + AbstractLdapTemplateIntegrationTest { @Autowired private LdapTemplate tested; private static String DN = "cn=Some Person4,ou=company1,c=Sweden"; @Test - public void testBindAndUnbind_Attributes_Plain() { + public void testBindAndUnbindWithAttributes() { Attributes attributes = setupAttributes(); tested.bind(DN, null, attributes); verifyBoundCorrectData(); @@ -59,7 +58,7 @@ public class LdapTemplateBindUnbindITest extends AbstractLdapTemplateIntegration } @Test - public void testBindAndUnbind_Attributes_DIstinguishedName() { + public void testBindAndUnbindWithAttributesUsingDistinguishedName() { Attributes attributes = setupAttributes(); tested.bind(new DistinguishedName(DN), null, attributes); verifyBoundCorrectData(); @@ -68,9 +67,10 @@ public class LdapTemplateBindUnbindITest extends AbstractLdapTemplateIntegration } @Test - public void testBindAndUnbind_DirContextAdapter_Plain() { + public void testBindAndUnbindWithDirContextAdapter() { DirContextAdapter adapter = new DirContextAdapter(); - adapter.setAttributeValues("objectclass", new String[] { "top", "person" }); + adapter.setAttributeValues("objectclass", new String[] { "top", + "person" }); adapter.setAttributeValue("cn", "Some Person4"); adapter.setAttributeValue("sn", "Person4"); @@ -81,9 +81,10 @@ public class LdapTemplateBindUnbindITest extends AbstractLdapTemplateIntegration } @Test - public void testBindAndUnbind_DirContextAdapter_DIstinguishedName() { + public void testBindAndUnbindWithDirContextAdapterUsingDistinguishedName() { DirContextAdapter adapter = new DirContextAdapter(); - adapter.setAttributeValues("objectclass", new String[] { "top", "person" }); + adapter.setAttributeValues("objectclass", new String[] { "top", + "person" }); adapter.setAttributeValue("cn", "Some Person4"); adapter.setAttributeValue("sn", "Person4"); @@ -94,9 +95,11 @@ public class LdapTemplateBindUnbindITest extends AbstractLdapTemplateIntegration } @Test - public void testBindAndUnbindPlainDirContextAdapter() { - DirContextAdapter adapter = new DirContextAdapter(new DistinguishedName(DN)); - adapter.setAttributeValues("objectclass", new String[] { "top", "person" }); + public void testBindAndUnbindWithDirContextAdapterOnly() { + DirContextAdapter adapter = new DirContextAdapter( + new DistinguishedName(DN)); + adapter.setAttributeValues("objectclass", new String[] { "top", + "person" }); adapter.setAttributeValue("cn", "Some Person4"); adapter.setAttributeValue("sn", "Person4"); @@ -106,6 +109,24 @@ public class LdapTemplateBindUnbindITest extends AbstractLdapTemplateIntegration verifyCleanup(); } + @Test + public void testBindAndRebindWithDirContextAdapterOnly() { + DirContextAdapter adapter = new DirContextAdapter( + new DistinguishedName(DN)); + adapter.setAttributeValues("objectclass", new String[] { "top", + "person" }); + adapter.setAttributeValue("cn", "Some Person4"); + adapter.setAttributeValue("sn", "Person4"); + + tested.bind(adapter); + verifyBoundCorrectData(); + adapter.setAttributeValue("sn", "Person4.Changed"); + tested.rebind(adapter); + verifyReboundCorrectData(); + tested.unbind(DN); + verifyCleanup(); + } + private Attributes setupAttributes() { Attributes attributes = new BasicAttributes(); BasicAttribute ocattr = new BasicAttribute("objectclass"); @@ -123,6 +144,12 @@ public class LdapTemplateBindUnbindITest extends AbstractLdapTemplateIntegration assertEquals("Person4", result.getStringAttribute("sn")); } + private void verifyReboundCorrectData() { + DirContextAdapter result = (DirContextAdapter) tested.lookup(DN); + assertEquals("Some Person4", result.getStringAttribute("cn")); + assertEquals("Person4.Changed", result.getStringAttribute("sn")); + } + private void verifyCleanup() { try { tested.lookup(DN);