org.springframework.ldap.LdapTemplate Maven / Gradle / Ivy
/*
* 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.List;
import javax.naming.Binding;
import javax.naming.Name;
import javax.naming.NameClassPair;
import javax.naming.NameNotFoundException;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.PartialResultException;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.ModificationItem;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import org.apache.commons.lang.Validate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
import org.springframework.ldap.support.DirContextAdapter;
import org.springframework.ldap.support.DistinguishedName;
/**
* Executes core LDAP functionality and helps to avoid common errors, relieving
* the user of the burden of looking up contexts, looping through
* NamingEnumerations and closing contexts.
*
* Note for Active Directory (AD) users: AD servers are apparently
* unable to handle referrals automatically, which causes a
* PartialResultException
to be thrown whenever a referral is
* encountered in a search. To avoid this, set the
* ignorePartialResultException
property to true
.
* There is currently no way of manually handling these referrals in the form of
* ReferralException
, i.e. either you get the exception (and
* your results are lost) or all referrals are ignored (if the server is unable
* to handle them properly. Neither is there any simple way to get notified that
* a PartialResultException
has been ignored (other than in the
* log).
*
* @see org.springframework.ldap.ContextSource
*
* @author Mattias Arthursson
* @author Ulrik Sandberg
*/
public class LdapTemplate implements LdapOperations, InitializingBean {
private static final Log log = LogFactory.getLog(LdapTemplate.class);
private static final int DEFAULT_SEARCH_SCOPE = SearchControls.SUBTREE_SCOPE;
private static final boolean DONT_RETURN_OBJ_FLAG = false;
private static final boolean RETURN_OBJ_FLAG = true;
private static final String[] ALL_ATTRIBUTES = null;
private ContextSource contextSource;
private NamingExceptionTranslator exceptionTranslator = new DefaultNamingExceptionTranslator();
private boolean ignorePartialResultException = false;
/**
* Constructor for bean usage.
*/
public LdapTemplate() {
}
/**
* Constructor to setup instance directly.
*
* @param contextSource
* the ContextSource to use.
*/
public LdapTemplate(ContextSource contextSource) {
this.contextSource = contextSource;
}
/**
* Set the ContextSource. Call this method when the default constructor has
* been used.
*
* @param contextSource
* the ContextSource.
*/
public void setContextSource(ContextSource contextSource) {
this.contextSource = contextSource;
}
/**
* Specify whether PartialResultException
should be ignored
* in searches. AD servers typically have a problem with referrals. Normally
* a referral should be followed automatically, but this does not seem to
* work with AD servers. The problem manifests itself with a a
* PartialResultException
being thrown when a referral is
* encountered by the server. Setting this property to true
* presents a workaround to this problem by causing
* PartialResultException
to be ignored, so that the search
* method returns normally. Default value of this parameter is
* false
.
*
* @param ignore
* true
if PartialResultException
* should be ignored in searches, false
otherwise.
* Default is false
.
*/
public void setIgnorePartialResultException(boolean ignore) {
this.ignorePartialResultException = ignore;
}
/*
* @see org.springframework.ldap.LdapOperations#search(javax.naming.Name,
* java.lang.String, int, boolean,
* org.springframework.ldap.NameClassPairCallbackHandler)
*/
public void search(Name base, String filter, int searchScope,
boolean returningObjFlag, NameClassPairCallbackHandler handler) {
search(base, filter, getDefaultSearchControls(searchScope,
returningObjFlag, ALL_ATTRIBUTES), handler);
}
/*
* @see org.springframework.ldap.LdapOperations#search(java.lang.String,
* java.lang.String, int, boolean,
* org.springframework.ldap.NameClassPairCallbackHandler)
*/
public void search(String base, String filter, int searchScope,
boolean returningObjFlag, NameClassPairCallbackHandler handler)
throws DataAccessException {
search(base, filter, getDefaultSearchControls(searchScope,
returningObjFlag, ALL_ATTRIBUTES), handler);
}
/*
* @see org.springframework.ldap.LdapOperations#search(javax.naming.Name,
* java.lang.String, javax.naming.directory.SearchControls,
* org.springframework.ldap.NameClassPairCallbackHandler)
*/
public void search(final Name base, final String filter,
final SearchControls controls, NameClassPairCallbackHandler handler) {
// Create a SearchExecutor to perform the search.
SearchExecutor se = new SearchExecutor() {
public NamingEnumeration executeSearch(DirContext ctx)
throws NamingException {
return ctx.search(base, filter, controls);
}
};
search(se, handler);
}
/*
* @see org.springframework.ldap.LdapOperations#search(java.lang.String,
* java.lang.String, javax.naming.directory.SearchControls,
* org.springframework.ldap.NameClassPairCallbackHandler)
*/
public void search(final String base, final String filter,
final SearchControls controls, NameClassPairCallbackHandler handler) {
// Create a SearchExecutor to perform the search.
SearchExecutor se = new SearchExecutor() {
public NamingEnumeration executeSearch(DirContext ctx)
throws NamingException {
return ctx.search(base, filter, controls);
}
};
search(se, handler);
}
/*
* @see org.springframework.ldap.LdapOperations#search(javax.naming.Name,
* java.lang.String, javax.naming.directory.SearchControls,
* org.springframework.ldap.NameClassPairCallbackHandler,
* org.springframework.ldap.DirContextProcessor)
*/
public void search(final Name base, final String filter,
final SearchControls controls,
NameClassPairCallbackHandler handler, DirContextProcessor processor) {
// Create a SearchExecutor to perform the search.
SearchExecutor se = new SearchExecutor() {
public NamingEnumeration executeSearch(DirContext ctx)
throws NamingException {
return ctx.search(base, filter, controls);
}
};
search(se, handler, processor);
}
/*
* @see org.springframework.ldap.LdapOperations#search(java.lang.String,
* java.lang.String, javax.naming.directory.SearchControls,
* org.springframework.ldap.NameClassPairCallbackHandler,
* org.springframework.ldap.DirContextProcessor)
*/
public void search(final String base, final String filter,
final SearchControls controls,
NameClassPairCallbackHandler handler, DirContextProcessor processor) {
// Create a SearchExecutor to perform the search.
SearchExecutor se = new SearchExecutor() {
public NamingEnumeration executeSearch(DirContext ctx)
throws NamingException {
return ctx.search(base, filter, controls);
}
};
search(se, handler, processor);
}
/**
* Perform a search operation, such as a search(), list() or listBindings().
* This method handles all the plumbing; getting a readonly context; looping
* through the NamingEnumeration and closing the context and enumeration. It
* also calls the supplied DirContextProcessor before and after the search,
* respectively. This enables custom pre-processing and post-processing,
* like for example when handling paged results or other search controls.
*
* The actual list is delegated to the {@link SearchExecutor} and each
* {@link NameClassPair} (this might be a NameClassPair or a subclass
* thereof) is passed to the CallbackHandler. Any encountered
* NamingException will be translated using the NamingExceptionTranslator.
*
* @param se
* the SearchExecutor to use for performing the actual list.
* @param handler
* the NameClassPairCallbackHandler to which each found entry
* will be passed.
* @param processor
* DirContextProcessor for custom pre- and post-processing. May
* be null
if no custom processing should take
* place.
* @throws DataAccessException
* if any error occurs. Note that a NameNotFoundException will
* be ignored. Instead this is interpreted that no entries were
* found.
*/
public void search(SearchExecutor se, NameClassPairCallbackHandler handler,
DirContextProcessor processor) {
DirContext ctx = contextSource.getReadOnlyContext();
NamingEnumeration results = null;
try {
processor.preProcess(ctx);
results = se.executeSearch(ctx);
while (results.hasMore()) {
NameClassPair result = (NameClassPair) results.next();
handler.handleNameClassPair(result);
}
processor.postProcess(ctx);
} catch (NameNotFoundException e) {
// The base context was not found, which basically means
// that the search did not return any results. Just clean up and
// exit.
} catch (PartialResultException e) {
// Workaround for AD servers not handling referrals correctly.
if (ignorePartialResultException) {
log.debug("PartialResultException encountered and ignored", e);
} else {
throw getExceptionTranslator().translate(e);
}
} catch (NamingException e) {
throw getExceptionTranslator().translate(e);
} finally {
closeContextAndNamingEnumeration(ctx, results);
}
}
/**
* Perform a search operation, such as a search(), list() or listBindings().
* This method handles all the plumbing; getting a readonly context; looping
* through the NamingEnumeration and closing the context and enumeration.
*
* The actual list is delegated to the {@link SearchExecutor} and each
* {@link NameClassPair} (this might be a NameClassPair or a subclass
* thereof) is passed to the CallbackHandler. Any encountered
* NamingException will be translated using the NamingExceptionTranslator.
*
* @param se
* the SearchExecutor to use for performing the actual list.
* @param handler
* the NameClassPairCallbackHandler to which each found entry
* will be passed.
* @throws DataAccessException
* if any error occurs. Note that a NameNotFoundException will
* be ignored. Instead this is interpreted that no entries were
* found.
*/
public void search(SearchExecutor se, NameClassPairCallbackHandler handler) {
search(se, handler, new NullDirContextProcessor());
}
/*
* @see org.springframework.ldap.LdapOperations#search(javax.naming.Name,
* java.lang.String,
* org.springframework.ldap.NameClassPairCallbackHandler)
*/
public void search(Name base, String filter,
NameClassPairCallbackHandler handler) throws DataAccessException {
search(base, filter, getDefaultSearchControls(DEFAULT_SEARCH_SCOPE,
DONT_RETURN_OBJ_FLAG, ALL_ATTRIBUTES), handler);
}
/*
* @see org.springframework.ldap.LdapOperations#search(java.lang.String,
* java.lang.String,
* org.springframework.ldap.NameClassPairCallbackHandler)
*/
public void search(String base, String filter,
NameClassPairCallbackHandler handler) throws DataAccessException {
search(base, filter, getDefaultSearchControls(DEFAULT_SEARCH_SCOPE,
DONT_RETURN_OBJ_FLAG, ALL_ATTRIBUTES), handler);
}
/*
* @see org.springframework.ldap.LdapOperations#search(javax.naming.Name,
* java.lang.String, int, java.lang.String[],
* org.springframework.ldap.AttributesMapper)
*/
public List search(Name base, String filter, int searchScope,
String[] attrs, AttributesMapper mapper) throws DataAccessException {
return search(base, filter, getDefaultSearchControls(searchScope,
DONT_RETURN_OBJ_FLAG, attrs), mapper);
}
/*
* @see org.springframework.ldap.LdapOperations#search(java.lang.String,
* java.lang.String, int, java.lang.String[],
* org.springframework.ldap.AttributesMapper)
*/
public List search(String base, String filter, int searchScope,
String[] attrs, AttributesMapper mapper) throws DataAccessException {
return search(base, filter, getDefaultSearchControls(searchScope,
DONT_RETURN_OBJ_FLAG, attrs), mapper);
}
/*
* @see org.springframework.ldap.LdapOperations#search(javax.naming.Name,
* java.lang.String, int, org.springframework.ldap.AttributesMapper)
*/
public List search(Name base, String filter, int searchScope,
AttributesMapper mapper) {
return search(base, filter, searchScope, ALL_ATTRIBUTES, mapper);
}
/*
* @see org.springframework.ldap.LdapOperations#search(java.lang.String,
* java.lang.String, int, org.springframework.ldap.AttributesMapper)
*/
public List search(String base, String filter, int searchScope,
AttributesMapper mapper) throws DataAccessException {
return search(base, filter, searchScope, ALL_ATTRIBUTES, mapper);
}
/*
* @see org.springframework.ldap.LdapOperations#search(javax.naming.Name,
* java.lang.String, org.springframework.ldap.AttributesMapper)
*/
public List search(Name base, String filter, AttributesMapper mapper)
throws DataAccessException {
return search(base, filter, DEFAULT_SEARCH_SCOPE, mapper);
}
/*
* @see org.springframework.ldap.LdapOperations#search(java.lang.String,
* java.lang.String, org.springframework.ldap.AttributesMapper)
*/
public List search(String base, String filter, AttributesMapper mapper)
throws DataAccessException {
return search(base, filter, DEFAULT_SEARCH_SCOPE, mapper);
}
/*
* @see org.springframework.ldap.LdapOperations#search(javax.naming.Name,
* java.lang.String, int, java.lang.String[],
* org.springframework.ldap.ContextMapper)
*/
public List search(Name base, String filter, int searchScope,
String[] attrs, ContextMapper mapper) throws DataAccessException {
return search(base, filter, getDefaultSearchControls(searchScope,
RETURN_OBJ_FLAG, attrs), mapper);
}
/*
* @see org.springframework.ldap.LdapOperations#search(java.lang.String,
* java.lang.String, int, java.lang.String[],
* org.springframework.ldap.ContextMapper)
*/
public List search(String base, String filter, int searchScope,
String[] attrs, ContextMapper mapper) throws DataAccessException {
return search(base, filter, getDefaultSearchControls(searchScope,
RETURN_OBJ_FLAG, attrs), mapper);
}
/*
* @see org.springframework.ldap.LdapOperations#search(javax.naming.Name,
* java.lang.String, int, org.springframework.ldap.ContextMapper)
*/
public List search(Name base, String filter, int searchScope,
ContextMapper mapper) {
return search(base, filter, searchScope, ALL_ATTRIBUTES, mapper);
}
/*
* @see org.springframework.ldap.LdapOperations#search(java.lang.String,
* java.lang.String, int, org.springframework.ldap.ContextMapper)
*/
public List search(String base, String filter, int searchScope,
ContextMapper mapper) throws DataAccessException {
return search(base, filter, searchScope, ALL_ATTRIBUTES, mapper);
}
/*
* @see org.springframework.ldap.LdapOperations#search(javax.naming.Name,
* java.lang.String, org.springframework.ldap.ContextMapper)
*/
public List search(Name base, String filter, ContextMapper mapper)
throws DataAccessException {
return search(base, filter, DEFAULT_SEARCH_SCOPE, mapper);
}
/*
* @see org.springframework.ldap.LdapOperations#search(java.lang.String,
* java.lang.String, org.springframework.ldap.ContextMapper)
*/
public List search(String base, String filter, ContextMapper mapper)
throws DataAccessException {
return search(base, filter, DEFAULT_SEARCH_SCOPE, mapper);
}
/*
* @see org.springframework.ldap.LdapOperations#search(java.lang.String,
* java.lang.String, javax.naming.directory.SearchControls,
* org.springframework.ldap.ContextMapper)
*/
public List search(String base, String filter, SearchControls controls,
ContextMapper mapper) {
return search(base, filter, controls, mapper,
new NullDirContextProcessor());
}
/*
* @see org.springframework.ldap.LdapOperations#search(javax.naming.Name,
* java.lang.String, javax.naming.directory.SearchControls,
* org.springframework.ldap.ContextMapper)
*/
public List search(Name base, String filter, SearchControls controls,
ContextMapper mapper) {
return search(base, filter, controls, mapper,
new NullDirContextProcessor());
}
/*
* @see org.springframework.ldap.LdapOperations#search(javax.naming.Name,
* java.lang.String, javax.naming.directory.SearchControls,
* org.springframework.ldap.AttributesMapper)
*/
public List search(Name base, String filter, SearchControls controls,
AttributesMapper mapper) {
return search(base, filter, controls, mapper,
new NullDirContextProcessor());
}
/*
* @see org.springframework.ldap.LdapOperations#search(java.lang.String,
* java.lang.String, javax.naming.directory.SearchControls,
* org.springframework.ldap.AttributesMapper)
*/
public List search(String base, String filter, SearchControls controls,
AttributesMapper mapper) {
return search(base, filter, controls, mapper,
new NullDirContextProcessor());
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.LdapOperations#search(java.lang.String,
* java.lang.String, javax.naming.directory.SearchControls,
* org.springframework.ldap.AttributesMapper,
* org.springframework.ldap.DirContextProcessor)
*/
public List search(String base, String filter, SearchControls controls,
AttributesMapper mapper, DirContextProcessor processor) {
AttributesMapperCallbackHandler handler = new AttributesMapperCallbackHandler(
mapper);
search(base, filter, controls, handler, processor);
return handler.getList();
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.LdapOperations#search(javax.naming.Name,
* java.lang.String, javax.naming.directory.SearchControls,
* org.springframework.ldap.AttributesMapper,
* org.springframework.ldap.DirContextProcessor)
*/
public List search(Name base, String filter, SearchControls controls,
AttributesMapper mapper, DirContextProcessor processor) {
AttributesMapperCallbackHandler handler = new AttributesMapperCallbackHandler(
mapper);
search(base, filter, controls, handler, processor);
return handler.getList();
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.LdapOperations#search(java.lang.String,
* java.lang.String, javax.naming.directory.SearchControls,
* org.springframework.ldap.ContextMapper,
* org.springframework.ldap.DirContextProcessor)
*/
public List search(String base, String filter, SearchControls controls,
ContextMapper mapper, DirContextProcessor processor) {
assureReturnObjFlagSet(controls);
ContextMapperCallbackHandler handler = new ContextMapperCallbackHandler(
mapper);
search(base, filter, controls, handler, processor);
return handler.getList();
}
/*
* (non-Javadoc)
*
* @see org.springframework.ldap.LdapOperations#search(javax.naming.Name,
* java.lang.String, javax.naming.directory.SearchControls,
* org.springframework.ldap.ContextMapper,
* org.springframework.ldap.DirContextProcessor)
*/
public List search(Name base, String filter, SearchControls controls,
ContextMapper mapper, DirContextProcessor processor) {
assureReturnObjFlagSet(controls);
ContextMapperCallbackHandler handler = new ContextMapperCallbackHandler(
mapper);
search(base, filter, controls, handler, processor);
return handler.getList();
}
/*
* @see org.springframework.ldap.LdapOperations#list(java.lang.String,
* org.springframework.ldap.ListResultCallbackHandler)
*/
public void list(final String base, NameClassPairCallbackHandler handler) {
SearchExecutor searchExecutor = new SearchExecutor() {
public NamingEnumeration executeSearch(DirContext ctx)
throws NamingException {
return ctx.list(base);
}
};
search(searchExecutor, handler);
}
/*
* @see org.springframework.ldap.LdapOperations#list(javax.naming.Name,
* org.springframework.ldap.ListResultCallbackHandler)
*/
public void list(final Name base, NameClassPairCallbackHandler handler) {
SearchExecutor searchExecutor = new SearchExecutor() {
public NamingEnumeration executeSearch(DirContext ctx)
throws NamingException {
return ctx.list(base);
}
};
search(searchExecutor, handler);
}
/*
* @see org.springframework.ldap.LdapOperations#list(java.lang.String,
* org.springframework.ldap.NameClassPairMapper)
*/
public List list(String base, NameClassPairMapper mapper) {
CollectingNameClassPairCallbackHandler handler = new MappingCollectingNameClassPairCallbackHandler(
mapper);
list(base, handler);
return handler.getList();
}
/*
* @see org.springframework.ldap.LdapOperations#list(javax.naming.Name,
* org.springframework.ldap.NameClassPairMapper)
*/
public List list(Name base, NameClassPairMapper mapper) {
CollectingNameClassPairCallbackHandler handler = new MappingCollectingNameClassPairCallbackHandler(
mapper);
list(base, handler);
return handler.getList();
}
/*
* @see org.springframework.ldap.LdapOperations#list(javax.naming.Name)
*/
public List list(final Name base) {
return list(base, new DefaultNameClassPairMapper());
}
/*
* @see org.springframework.ldap.LdapOperations#list(java.lang.String)
*/
public List list(final String base) {
return list(base, new DefaultNameClassPairMapper());
}
/*
* @see org.springframework.ldap.LdapOperations#listBindings(java.lang.String,
* org.springframework.ldap.NameClassPairCallbackHandler)
*/
public void listBindings(final String base,
NameClassPairCallbackHandler handler) {
SearchExecutor searchExecutor = new SearchExecutor() {
public NamingEnumeration executeSearch(DirContext ctx)
throws NamingException {
return ctx.listBindings(base);
}
};
search(searchExecutor, handler);
}
/*
* @see org.springframework.ldap.LdapOperations#listBindings(javax.naming.Name,
* org.springframework.ldap.NameClassPairCallbackHandler)
*/
public void listBindings(final Name base,
NameClassPairCallbackHandler handler) {
SearchExecutor searchExecutor = new SearchExecutor() {
public NamingEnumeration executeSearch(DirContext ctx)
throws NamingException {
return ctx.listBindings(base);
}
};
search(searchExecutor, handler);
}
/*
* @see org.springframework.ldap.LdapOperations#listBindings(java.lang.String,
* org.springframework.ldap.NameClassPairMapper)
*/
public List listBindings(String base, NameClassPairMapper mapper) {
CollectingNameClassPairCallbackHandler handler = new MappingCollectingNameClassPairCallbackHandler(
mapper);
listBindings(base, handler);
return handler.getList();
}
/*
* @see org.springframework.ldap.LdapOperations#listBindings(javax.naming.Name,
* org.springframework.ldap.NameClassPairMapper)
*/
public List listBindings(Name base, NameClassPairMapper mapper) {
CollectingNameClassPairCallbackHandler handler = new MappingCollectingNameClassPairCallbackHandler(
mapper);
listBindings(base, handler);
return handler.getList();
}
/*
* @see org.springframework.ldap.LdapOperations#listBindings(java.lang.String)
*/
public List listBindings(final String base) {
return listBindings(base, new DefaultNameClassPairMapper());
}
/*
* @see org.springframework.ldap.LdapOperations#listBindings(javax.naming.Name)
*/
public List listBindings(final Name base) {
return listBindings(base, new DefaultNameClassPairMapper());
}
/*
* @see org.springframework.ldap.LdapOperations#listBindings(java.lang.String,
* org.springframework.ldap.ContextMapper)
*/
public List listBindings(String base, ContextMapper mapper) {
ContextMapperCallbackHandler handler = new ContextMapperCallbackHandler(
mapper);
listBindings(base, handler);
return handler.getList();
}
/*
* @see org.springframework.ldap.LdapOperations#listBindings(javax.naming.Name,
* org.springframework.ldap.ContextMapper)
*/
public List listBindings(Name base, ContextMapper mapper) {
ContextMapperCallbackHandler handler = new ContextMapperCallbackHandler(
mapper);
listBindings(base, handler);
return handler.getList();
}
/*
* @see org.springframework.ldap.LdapOperations#executeReadOnly(org.springframework.ldap.ContextExecutor)
*/
public Object executeReadOnly(ContextExecutor ce) {
DirContext ctx = contextSource.getReadOnlyContext();
return executeWithContext(ce, ctx);
}
/*
* @see org.springframework.ldap.LdapOperations#executeReadWrite(org.springframework.ldap.ContextExecutor)
*/
public Object executeReadWrite(ContextExecutor ce) {
DirContext ctx = contextSource.getReadWriteContext();
return executeWithContext(ce, ctx);
}
private Object executeWithContext(ContextExecutor ce, DirContext ctx) {
try {
return ce.executeWithContext(ctx);
} catch (NamingException e) {
throw getExceptionTranslator().translate(e);
} finally {
closeContext(ctx);
}
}
/*
* @see org.springframework.ldap.LdapOperations#lookup(javax.naming.Name)
*/
public Object lookup(final Name dn) {
return executeReadOnly(new ContextExecutor() {
public Object executeWithContext(DirContext ctx)
throws NamingException {
return ctx.lookup(dn);
}
});
}
/*
* @see org.springframework.ldap.LdapOperations#lookup(java.lang.String)
*/
public Object lookup(final String dn) throws DataAccessException {
return executeReadOnly(new ContextExecutor() {
public Object executeWithContext(DirContext ctx)
throws NamingException {
return ctx.lookup(dn);
}
});
}
/*
* @see org.springframework.ldap.LdapOperations#lookup(javax.naming.Name,
* org.springframework.ldap.AttributesMapper)
*/
public Object lookup(final Name dn, final AttributesMapper mapper) {
return executeReadOnly(new ContextExecutor() {
public Object executeWithContext(DirContext ctx)
throws NamingException {
Attributes attributes = ctx.getAttributes(dn);
return mapper.mapFromAttributes(attributes);
}
});
}
/*
* @see org.springframework.ldap.LdapOperations#lookup(java.lang.String,
* org.springframework.ldap.AttributesMapper)
*/
public Object lookup(final String dn, final AttributesMapper mapper)
throws DataAccessException {
return executeReadOnly(new ContextExecutor() {
public Object executeWithContext(DirContext ctx)
throws NamingException {
Attributes attributes = ctx.getAttributes(dn);
return mapper.mapFromAttributes(attributes);
}
});
}
/*
* @see org.springframework.ldap.LdapOperations#lookup(javax.naming.Name,
* org.springframework.ldap.ContextMapper)
*/
public Object lookup(final Name dn, final ContextMapper mapper) {
return executeReadOnly(new ContextExecutor() {
public Object executeWithContext(DirContext ctx)
throws NamingException {
Object object = ctx.lookup(dn);
return mapper.mapFromContext(object);
}
});
}
/*
* @see org.springframework.ldap.LdapOperations#lookup(java.lang.String,
* org.springframework.ldap.ContextMapper)
*/
public Object lookup(final String dn, final ContextMapper mapper)
throws DataAccessException {
return executeReadOnly(new ContextExecutor() {
public Object executeWithContext(DirContext ctx)
throws NamingException {
Object object = ctx.lookup(dn);
return mapper.mapFromContext(object);
}
});
}
/*
* @see org.springframework.ldap.LdapOperations#lookup(javax.naming.Name,
* java.lang.String[], org.springframework.ldap.AttributesMapper)
*/
public Object lookup(final Name dn, final String[] attributes,
final AttributesMapper mapper) throws DataAccessException {
return executeReadOnly(new ContextExecutor() {
public Object executeWithContext(DirContext ctx)
throws NamingException {
Attributes filteredAttributes = ctx.getAttributes(dn,
attributes);
return mapper.mapFromAttributes(filteredAttributes);
}
});
}
/*
* @see org.springframework.ldap.LdapOperations#lookup(java.lang.String,
* java.lang.String[], org.springframework.ldap.AttributesMapper)
*/
public Object lookup(final String dn, final String[] attributes,
final AttributesMapper mapper) throws DataAccessException {
return executeReadOnly(new ContextExecutor() {
public Object executeWithContext(DirContext ctx)
throws NamingException {
Attributes filteredAttributes = ctx.getAttributes(dn,
attributes);
return mapper.mapFromAttributes(filteredAttributes);
}
});
}
/*
* @see org.springframework.ldap.LdapOperations#lookup(javax.naming.Name,
* java.lang.String[], org.springframework.ldap.ContextMapper)
*/
public Object lookup(final Name dn, final String[] attributes,
final ContextMapper mapper) throws DataAccessException {
return executeReadOnly(new ContextExecutor() {
public Object executeWithContext(DirContext ctx)
throws NamingException {
Attributes filteredAttributes = ctx.getAttributes(dn,
attributes);
DirContextAdapter contextAdapter = new DirContextAdapter(
filteredAttributes, dn);
return mapper.mapFromContext(contextAdapter);
}
});
}
/*
* @see org.springframework.ldap.LdapOperations#lookup(java.lang.String,
* java.lang.String[], org.springframework.ldap.ContextMapper)
*/
public Object lookup(final String dn, final String[] attributes,
final ContextMapper mapper) throws DataAccessException {
return executeReadOnly(new ContextExecutor() {
public Object executeWithContext(DirContext ctx)
throws NamingException {
Attributes filteredAttributes = ctx.getAttributes(dn,
attributes);
DistinguishedName name = new DistinguishedName(dn);
DirContextAdapter contextAdapter = new DirContextAdapter(
filteredAttributes, name);
return mapper.mapFromContext(contextAdapter);
}
});
}
/*
* @see org.springframework.ldap.LdapOperations#modifyAttributes(javax.naming.Name,
* javax.naming.directory.ModificationItem[])
*/
public void modifyAttributes(final Name dn, final ModificationItem[] mods) {
executeReadWrite(new ContextExecutor() {
public Object executeWithContext(DirContext ctx)
throws NamingException {
ctx.modifyAttributes(dn, mods);
return null;
}
});
}
/*
* @see org.springframework.ldap.LdapOperations#modifyAttributes(java.lang.String,
* javax.naming.directory.ModificationItem[])
*/
public void modifyAttributes(final String dn, final ModificationItem[] mods)
throws DataAccessException {
executeReadWrite(new ContextExecutor() {
public Object executeWithContext(DirContext ctx)
throws NamingException {
ctx.modifyAttributes(dn, mods);
return null;
}
});
}
/*
* @see org.springframework.ldap.LdapOperations#bind(javax.naming.Name,
* java.lang.Object, javax.naming.directory.Attributes)
*/
public void bind(final Name dn, final Object obj,
final Attributes attributes) {
executeReadWrite(new ContextExecutor() {
public Object executeWithContext(DirContext ctx)
throws NamingException {
ctx.bind(dn, obj, attributes);
return null;
}
});
}
/*
* @see org.springframework.ldap.LdapOperations#bind(java.lang.String,
* java.lang.Object, javax.naming.directory.Attributes)
*/
public void bind(final String dn, final Object obj,
final Attributes attributes) throws DataAccessException {
executeReadWrite(new ContextExecutor() {
public Object executeWithContext(DirContext ctx)
throws NamingException {
ctx.bind(dn, obj, attributes);
return null;
}
});
}
/*
* @see org.springframework.ldap.LdapOperations#unbind(javax.naming.Name)
*/
public void unbind(final Name dn) {
doUnbind(dn);
}
/*
* @see org.springframework.ldap.LdapOperations#unbind(java.lang.String)
*/
public void unbind(final String dn) throws DataAccessException {
doUnbind(dn);
}
/*
* @see org.springframework.ldap.LdapOperations#unbind(javax.naming.Name,
* boolean)
*/
public void unbind(final Name dn, boolean recursive)
throws DataAccessException {
if (!recursive) {
doUnbind(dn);
} else {
doUnbindRecursively(dn);
}
}
/*
* @see org.springframework.ldap.LdapOperations#unbind(java.lang.String,
* boolean)
*/
public void unbind(final String dn, boolean recursive)
throws DataAccessException {
if (!recursive) {
doUnbind(dn);
} else {
doUnbindRecursively(dn);
}
}
private void doUnbind(final Name dn) throws DataAccessException {
executeReadWrite(new ContextExecutor() {
public Object executeWithContext(DirContext ctx)
throws NamingException {
ctx.unbind(dn);
return null;
}
});
}
private void doUnbind(final String dn) throws DataAccessException {
executeReadWrite(new ContextExecutor() {
public Object executeWithContext(DirContext ctx)
throws NamingException {
ctx.unbind(dn);
return null;
}
});
}
private void doUnbindRecursively(final Name dn) throws DataAccessException {
executeReadWrite(new ContextExecutor() {
public Object executeWithContext(DirContext ctx)
throws NamingException {
deleteRecursively(ctx, new DistinguishedName(dn));
return null;
}
});
}
private void doUnbindRecursively(final String dn)
throws DataAccessException {
executeReadWrite(new ContextExecutor() {
public Object executeWithContext(DirContext ctx)
throws NamingException {
deleteRecursively(ctx, new DistinguishedName(dn));
return null;
}
});
}
/**
* Delete all subcontexts including the current one recursively.
*
* @param ctx
* The context to use for deleting.
* @param name
* The starting point to delete recursively.
* @throws DataAccessException
* if any error occurs
*/
protected void deleteRecursively(DirContext ctx, DistinguishedName name)
throws DataAccessException {
NamingEnumeration enumeration = null;
try {
enumeration = ctx.listBindings(name);
while (enumeration.hasMore()) {
Binding binding = (Binding) enumeration.next();
DistinguishedName childName = new DistinguishedName(binding
.getName());
childName.prepend((DistinguishedName) name);
deleteRecursively(ctx, childName);
}
ctx.unbind(name);
if (log.isDebugEnabled()) {
log.debug("Entry " + name + " deleted");
}
} catch (NamingException e) {
throw getExceptionTranslator().translate(e);
} finally {
try {
enumeration.close();
} catch (Exception e) {
// Never mind this
}
}
}
/*
* @see org.springframework.ldap.LdapOperations#rebind(javax.naming.Name,
* java.lang.Object, javax.naming.directory.Attributes)
*/
public void rebind(final Name dn, final Object obj,
final Attributes attributes) throws DataAccessException {
executeReadWrite(new ContextExecutor() {
public Object executeWithContext(DirContext ctx)
throws NamingException {
ctx.rebind(dn, obj, attributes);
return null;
}
});
}
/*
* @see org.springframework.ldap.LdapOperations#rebind(java.lang.String,
* java.lang.Object, javax.naming.directory.Attributes)
*/
public void rebind(final String dn, final Object obj,
final Attributes attributes) throws DataAccessException {
executeReadWrite(new ContextExecutor() {
public Object executeWithContext(DirContext ctx)
throws NamingException {
ctx.rebind(dn, obj, attributes);
return null;
}
});
}
/*
* @see org.springframework.ldap.LdapOperations#rename(javax.naming.Name,
* javax.naming.Name)
*/
public void rename(final Name oldDn, final Name newDn)
throws DataAccessException {
executeReadWrite(new ContextExecutor() {
public Object executeWithContext(DirContext ctx)
throws NamingException {
ctx.rename(oldDn, newDn);
return null;
}
});
}
/*
* @see org.springframework.ldap.LdapOperations#rename(java.lang.String,
* java.lang.String)
*/
public void rename(final String oldDn, final String newDn)
throws DataAccessException {
executeReadWrite(new ContextExecutor() {
public Object executeWithContext(DirContext ctx)
throws NamingException {
ctx.rename(oldDn, newDn);
return null;
}
});
}
/*
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
public void afterPropertiesSet() throws Exception {
if (contextSource == null) {
throw new IllegalArgumentException(
"Property 'contextSource' must be set.");
}
}
private void closeContextAndNamingEnumeration(DirContext ctx,
NamingEnumeration results) {
closeNamingEnumeration(results);
closeContext(ctx);
}
/**
* Close the supplied DirContext if it is not null. Swallow any exceptions,
* as this is only for cleanup.
*
* @param ctx
* the context to close.
*/
private void closeContext(DirContext ctx) {
if (ctx != null) {
try {
ctx.close();
} catch (Exception e) {
// Never mind this.
}
}
}
/**
* Close the supplied NamingEnumeration if it is not null. Swallow any
* exceptions, as this is only for cleanup.
*
* @param results
* the NamingEnumeration to close.
*/
private void closeNamingEnumeration(NamingEnumeration results) {
if (results != null) {
try {
results.close();
} catch (Exception e) {
// Never mind this.
}
}
}
/**
* Get the NamingExceptionTranslator that will be used by this instance. If
* no exceptionTranslator has been set, a default instance will be created.
*
* @return the NamingExceptionTranslator to be used by this instance.
*/
public NamingExceptionTranslator getExceptionTranslator() {
return exceptionTranslator;
}
/**
* Set the NamingExceptionTranslator to be used by this instance.
*
* @param exceptionTranslator
* the NamingExceptionTranslator to use.
*/
public void setExceptionTranslator(
NamingExceptionTranslator exceptionTranslator) {
this.exceptionTranslator = exceptionTranslator;
}
private SearchControls getDefaultSearchControls(int searchScope,
boolean returningObjFlag, String[] attrs) {
SearchControls controls = new SearchControls();
controls.setSearchScope(searchScope);
controls.setReturningObjFlag(returningObjFlag);
controls.setReturningAttributes(attrs);
return controls;
}
/**
* Make sure the returnObjFlag is set in the supplied SearchControls. Set it
* and log if it's not set.
*
* @param controls
* the SearchControls to check.
*/
private void assureReturnObjFlagSet(SearchControls controls) {
Validate.notNull(controls);
if (!controls.getReturningObjFlag()) {
log.info("The returnObjFlag of supplied SearchControls is not set"
+ " but a ContextMapper is used - setting flag to true");
controls.setReturningObjFlag(true);
}
}
private final class NullDirContextProcessor implements DirContextProcessor {
public void postProcess(DirContext ctx) throws NamingException {
// Do nothing
}
public void preProcess(DirContext ctx) throws NamingException {
// Do nothing
}
}
/**
* A {@link NameClassPairCallbackHandler} that passes the NameClassPairs
* found to a NameClassPairMapper and collects the results in a list.
*
* @author Mattias Arthursson
*/
public class MappingCollectingNameClassPairCallbackHandler extends
CollectingNameClassPairCallbackHandler {
private NameClassPairMapper mapper;
public MappingCollectingNameClassPairCallbackHandler(
NameClassPairMapper mapper) {
this.mapper = mapper;
}
/*
* @see org.springframework.ldap.CollectingNameClassPairCallbackHandler#getObjectFromNameClassPair(javax.naming.NameClassPair)
*/
public Object getObjectFromNameClassPair(NameClassPair nameClassPair) {
try {
return mapper.mapFromNameClassPair(nameClassPair);
} catch (NamingException e) {
throw getExceptionTranslator().translate(e);
}
}
}
/**
* A CollectingNameClassPairCallbackHandler to wrap an AttributesMapper.
* That is, the found object is extracted from the {@link Attributes} of
* each {@link SearchResult}, and then passed to the specified
* AttributesMapper for translation. This class needs to be nested, since we
* want to be able to get hold of the exception translator of this instance.
*
* @author Mattias Arthursson
* @author Ulrik Sandberg
*/
public class AttributesMapperCallbackHandler extends
CollectingNameClassPairCallbackHandler {
private AttributesMapper mapper;
public AttributesMapperCallbackHandler(AttributesMapper mapper) {
this.mapper = mapper;
}
/**
* Cast the NameClassPair to a SearchResult and pass its attributes to
* the AttributesMapper.
*
* @param nameClassPair
* a SearchResult instance.
* @return the Object returned from the Mapper.
*/
public Object getObjectFromNameClassPair(NameClassPair nameClassPair) {
SearchResult searchResult = (SearchResult) nameClassPair;
Attributes attributes = searchResult.getAttributes();
try {
return mapper.mapFromAttributes(attributes);
} catch (NamingException e) {
throw getExceptionTranslator().translate(e);
}
}
}
/**
* A CollectingNameClassPairCallbackHandler to wrap a ContextMapper. That
* is, the found object is extracted from each {@link Binding}, and then
* passed to the specified ContextMapper for translation.
*
* @author Mattias Arthursson
* @author Ulrik Sandberg
*/
public class ContextMapperCallbackHandler extends
CollectingNameClassPairCallbackHandler {
private ContextMapper mapper;
public ContextMapperCallbackHandler(ContextMapper mapper) {
this.mapper = mapper;
}
/**
* Cast the NameClassPair to a {@link Binding} and pass its attributes
* to the ContextMapper.
*
* @param nameClassPair
* a SearchResult instance.
* @return the Object returned from the Mapper.
*/
public Object getObjectFromNameClassPair(NameClassPair nameClassPair) {
Binding binding = (Binding) nameClassPair;
Object object = binding.getObject();
if (object == null) {
throw new EntryNotFoundException(
"SearchResult did not contain any object.");
}
return mapper.mapFromContext(object);
}
}
}