Fix for LDAP-78: add lookupContext and alternate modifyAttributes in LdapOperations
This commit is contained in:
@@ -24,6 +24,7 @@ import javax.naming.NameClassPair;
|
||||
import javax.naming.directory.Attributes;
|
||||
import javax.naming.directory.ModificationItem;
|
||||
import javax.naming.directory.SearchControls;
|
||||
import javax.naming.spi.DirObjectFactory;
|
||||
|
||||
import org.springframework.ldap.ContextNotEmptyException;
|
||||
import org.springframework.ldap.NamingException;
|
||||
@@ -1017,34 +1018,30 @@ public interface LdapOperations {
|
||||
throws NamingException;
|
||||
|
||||
/**
|
||||
* Lookup the supplied DN and return the found object. <b>WARNING</b>: This
|
||||
* method should only be used if a DirObjectFactory has been specified on
|
||||
* the ContextFactory. If this is not the case, you will get a new instance
|
||||
* of the actual DirContext, which is probably not what you want. If,
|
||||
* however this <b>is</b> what you want, be careful to close the context
|
||||
* after you finished working with it.
|
||||
* Lookup the supplied DN and return the found object. This will typically
|
||||
* be a {@link DirContextAdapter}, unless the DirObjectFactory has been
|
||||
* modified in the ContextSource.
|
||||
*
|
||||
* @param dn
|
||||
* The distinguished name of the object to find.
|
||||
* @return the found object.
|
||||
* @return the found object, typically a {@link DirContextAdapter} instance.
|
||||
* @throws NamingException
|
||||
* if any error occurs.
|
||||
* @see #lookupContext(Name)
|
||||
*/
|
||||
public Object lookup(Name dn) throws NamingException;
|
||||
|
||||
/**
|
||||
* Lookup the supplied DN and return the found object. <b>WARNING</b>: This
|
||||
* method should only be used if a DirObjectFactory has been specified on
|
||||
* the ContextFactory. If this is not the case, you will get a new instance
|
||||
* of the actual DirContext, which is probably not what you want. If,
|
||||
* however this <b>is</b> what you want, be careful to close the context
|
||||
* after you finished working with it.
|
||||
* Lookup the supplied DN and return the found object. This will typically
|
||||
* be a {@link DirContextAdapter}, unless the DirObjectFactory has been
|
||||
* modified in the ContextSource.
|
||||
*
|
||||
* @param dn
|
||||
* The distinguished name of the object to find.
|
||||
* @return the found object.
|
||||
* @return the found object, typically a {@link DirContextAdapter} instance.
|
||||
* @throws NamingException
|
||||
* if any error occurs.
|
||||
* @see #lookupContext(Name)
|
||||
*/
|
||||
public Object lookup(String dn) throws NamingException;
|
||||
|
||||
@@ -1366,4 +1363,77 @@ public interface LdapOperations {
|
||||
*/
|
||||
public void rename(final String oldDn, final String newDn)
|
||||
throws NamingException;
|
||||
|
||||
/**
|
||||
* Convenience method to lookup the supplied DN and automatically cast it to
|
||||
* {@link DirContextOperations}.
|
||||
*
|
||||
* @param dn
|
||||
* The distinguished name of the object to find.
|
||||
* @return The found object, cast to {@link DirContextOperations}.
|
||||
* @throws ClassCastException
|
||||
* if an alternative DirObjectFactory has been registered woth
|
||||
* the ContextSource, causing the actual class of the returned
|
||||
* object to be something else than {@link DirContextOperations}.
|
||||
* @throws NamingException
|
||||
* if any other error occurs.
|
||||
* @see #lookup(Name)
|
||||
*/
|
||||
public DirContextOperations lookupContext(Name dn) throws NamingException,
|
||||
ClassCastException;
|
||||
|
||||
/**
|
||||
* Convenience method to lookup the supplied DN and automatically cast it to
|
||||
* {@link DirContextOperations}.
|
||||
*
|
||||
* @param dn
|
||||
* The distinguished name of the object to find.
|
||||
* @return The found object, cast to {@link DirContextOperations}.
|
||||
* @throws ClassCastException
|
||||
* if an alternative DirObjectFactory has been registered woth
|
||||
* the ContextSource, causing the actual class of the returned
|
||||
* object to be something else than {@link DirContextOperations}.
|
||||
* @throws NamingException
|
||||
* if any other error occurs.
|
||||
* @see #lookup(String)
|
||||
*/
|
||||
public DirContextOperations lookupContext(String dn)
|
||||
throws NamingException, ClassCastException;
|
||||
|
||||
/**
|
||||
* Modify the attributes of the entry referenced by the supplied
|
||||
* {@link DirContextOperations} instance. The DN to update will be the DN of
|
||||
* the <code>DirContextOperations</code>instance, and the
|
||||
* <code>ModificationItem</code> array is retrieved from the
|
||||
* <code>DirContextOperations</code> instance using a call to
|
||||
* {@link AttributeModificationsAware#getModificationItems()}. <b>NB:</b>
|
||||
* The supplied instance needs to have been properly initialized; this means
|
||||
* that if it hasn't been received from a <code>lookup</code> operation,
|
||||
* its DN needs to be initialized and it must have been put in update mode ({@link DirContextAdapter#setUpdateMode(boolean)}).
|
||||
* <p>
|
||||
* Typical use of this method would be as follows:
|
||||
*
|
||||
* <pre>
|
||||
* public void update(Person person) {
|
||||
* DirContextOperations ctx = ldapOperations.lookupContext(person.getDn());
|
||||
*
|
||||
* ctx.setAttributeValue("description", person.getDescription());
|
||||
* ctx.setAttributeValue("telephoneNumber", person.getPhone());
|
||||
* // More modifications here
|
||||
*
|
||||
* ldapOperations.modifyAttributes(ctx);
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param ctx
|
||||
* the DirContextOperations instance to use in the update.
|
||||
* @throws IllegalStateException
|
||||
* if the supplied instance is not in update mode or has not
|
||||
* been properly initialized.
|
||||
* @throws NamingException
|
||||
* if any other error occurs.
|
||||
*
|
||||
*/
|
||||
public void modifyAttributes(DirContextOperations ctx)
|
||||
throws IllegalStateException, NamingException;
|
||||
}
|
||||
|
||||
@@ -1294,4 +1294,23 @@ public class LdapTemplate implements LdapOperations, InitializingBean {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public DirContextOperations lookupContext(Name dn) {
|
||||
return (DirContextOperations) lookup(dn);
|
||||
}
|
||||
|
||||
public DirContextOperations lookupContext(String dn) {
|
||||
return (DirContextOperations) lookup(dn);
|
||||
}
|
||||
|
||||
public void modifyAttributes(DirContextOperations ctx) {
|
||||
Name dn = ctx.getDn();
|
||||
if (dn != null && ctx.isUpdateMode()) {
|
||||
modifyAttributes(dn, ctx.getModificationItems());
|
||||
} else {
|
||||
throw new IllegalStateException(
|
||||
"The DirContextOperations instance needs to be properly initialized.");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,6 +82,10 @@ public class LdapTemplateTest extends TestCase {
|
||||
|
||||
private DirContextProcessor dirContextProcessorMock;
|
||||
|
||||
private MockControl dirContextOperationsConrol;
|
||||
|
||||
private DirContextOperations dirContextOperationsMock;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
@@ -129,6 +133,11 @@ public class LdapTemplateTest extends TestCase {
|
||||
dirContextProcessorMock = (DirContextProcessor) dirContextProcessorControl
|
||||
.getMock();
|
||||
|
||||
dirContextOperationsConrol = MockControl
|
||||
.createControl(DirContextOperations.class);
|
||||
dirContextOperationsMock = (DirContextOperations) dirContextOperationsConrol
|
||||
.getMock();
|
||||
|
||||
tested = new LdapTemplate(contextSourceMock);
|
||||
}
|
||||
|
||||
@@ -164,6 +173,10 @@ public class LdapTemplateTest extends TestCase {
|
||||
|
||||
dirContextProcessorControl = null;
|
||||
dirContextProcessorMock = null;
|
||||
|
||||
dirContextOperationsConrol = null;
|
||||
dirContextOperationsMock = null;
|
||||
|
||||
}
|
||||
|
||||
protected void replay() {
|
||||
@@ -177,6 +190,7 @@ public class LdapTemplateTest extends TestCase {
|
||||
contextExecutorControl.replay();
|
||||
searchExecutorControl.replay();
|
||||
dirContextProcessorControl.replay();
|
||||
dirContextOperationsConrol.replay();
|
||||
}
|
||||
|
||||
protected void verify() {
|
||||
@@ -190,6 +204,7 @@ public class LdapTemplateTest extends TestCase {
|
||||
contextExecutorControl.verify();
|
||||
searchExecutorControl.verify();
|
||||
dirContextProcessorControl.verify();
|
||||
dirContextOperationsConrol.verify();
|
||||
}
|
||||
|
||||
private void expectGetReadWriteContext() {
|
||||
@@ -1584,7 +1599,8 @@ public class LdapTemplateTest extends TestCase {
|
||||
expectGetReadOnlyContext();
|
||||
|
||||
searchExecutorControl.expectAndThrow(searchExecutorMock
|
||||
.executeSearch(dirContextMock), new javax.naming.NameNotFoundException());
|
||||
.executeSearch(dirContextMock),
|
||||
new javax.naming.NameNotFoundException());
|
||||
dirContextMock.close();
|
||||
|
||||
replay();
|
||||
@@ -1639,6 +1655,111 @@ public class LdapTemplateTest extends TestCase {
|
||||
verify();
|
||||
}
|
||||
|
||||
public void testLookupContextWithName() {
|
||||
final DirContextAdapter expectedResult = new DirContextAdapter();
|
||||
|
||||
LdapTemplate tested = new LdapTemplate() {
|
||||
public Object lookup(Name dn) {
|
||||
assertSame(DistinguishedName.EMPTY_PATH, dn);
|
||||
return expectedResult;
|
||||
}
|
||||
};
|
||||
|
||||
DirContextOperations result = tested
|
||||
.lookupContext(DistinguishedName.EMPTY_PATH);
|
||||
assertSame(expectedResult, result);
|
||||
|
||||
}
|
||||
|
||||
public void testLookupContextWithString() {
|
||||
final DirContextAdapter expectedResult = new DirContextAdapter();
|
||||
final String expectedName = "cn=John Doe";
|
||||
|
||||
LdapTemplate tested = new LdapTemplate() {
|
||||
public Object lookup(String dn) {
|
||||
assertSame(expectedName, dn);
|
||||
return expectedResult;
|
||||
}
|
||||
};
|
||||
|
||||
DirContextOperations result = tested.lookupContext(expectedName);
|
||||
assertSame(expectedResult, result);
|
||||
}
|
||||
|
||||
public void testModifyAttributesWithDirContextOperations() throws Exception {
|
||||
final ModificationItem[] expectedModifications = new ModificationItem[0];
|
||||
|
||||
dirContextOperationsConrol.expectAndReturn(dirContextOperationsMock
|
||||
.getDn(), DistinguishedName.EMPTY_PATH);
|
||||
dirContextOperationsConrol.expectAndReturn(dirContextOperationsMock
|
||||
.isUpdateMode(), true);
|
||||
dirContextOperationsConrol.expectAndReturn(dirContextOperationsMock
|
||||
.getModificationItems(), expectedModifications);
|
||||
|
||||
LdapTemplate tested = new LdapTemplate() {
|
||||
public void modifyAttributes(Name dn, ModificationItem[] mods) {
|
||||
assertSame(DistinguishedName.EMPTY_PATH, dn);
|
||||
assertSame(expectedModifications, mods);
|
||||
}
|
||||
};
|
||||
|
||||
replay();
|
||||
|
||||
tested.modifyAttributes(dirContextOperationsMock);
|
||||
|
||||
verify();
|
||||
}
|
||||
|
||||
public void testModifyAttributesWithDirContextOperationsNotInitializedDn()
|
||||
throws Exception {
|
||||
final ModificationItem[] expectedModifications = new ModificationItem[0];
|
||||
|
||||
dirContextOperationsConrol.expectAndReturn(dirContextOperationsMock
|
||||
.getDn(), DistinguishedName.EMPTY_PATH);
|
||||
dirContextOperationsConrol.expectAndReturn(dirContextOperationsMock
|
||||
.isUpdateMode(), false);
|
||||
|
||||
LdapTemplate tested = new LdapTemplate() {
|
||||
public void modifyAttributes(Name dn, ModificationItem[] mods) {
|
||||
fail("The call to the base modifyAttributes should not have occured.");
|
||||
}
|
||||
};
|
||||
|
||||
replay();
|
||||
|
||||
try {
|
||||
tested.modifyAttributes(dirContextOperationsMock);
|
||||
fail("IllegalStateException expected");
|
||||
} catch (IllegalStateException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
verify();
|
||||
}
|
||||
|
||||
public void testModifyAttributesWithDirContextOperationsNotInitializedInUpdateMode()
|
||||
throws Exception {
|
||||
final ModificationItem[] expectedModifications = new ModificationItem[0];
|
||||
|
||||
dirContextOperationsConrol.expectAndReturn(dirContextOperationsMock
|
||||
.getDn(), null);
|
||||
|
||||
LdapTemplate tested = new LdapTemplate() {
|
||||
public void modifyAttributes(Name dn, ModificationItem[] mods) {
|
||||
fail("The call to the base modifyAttributes should not have occured.");
|
||||
}
|
||||
};
|
||||
|
||||
replay();
|
||||
|
||||
try {
|
||||
tested.modifyAttributes(dirContextOperationsMock);
|
||||
fail("IllegalStateException expected");
|
||||
} catch (IllegalStateException expected) {
|
||||
assertTrue(true);
|
||||
}
|
||||
verify();
|
||||
}
|
||||
|
||||
/**
|
||||
* Needed to verify search control values.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user