Java tutorial
/* * Copyright 2005-2010 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.core; 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.PartialResultException; import javax.naming.directory.Attributes; import javax.naming.directory.DirContext; import javax.naming.directory.ModificationItem; import javax.naming.directory.SearchControls; 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.EmptyResultDataAccessException; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.ldap.NamingException; import org.springframework.ldap.support.LdapUtils; /** * 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. * <p> * <b>Note for Active Directory (AD) users:</b> AD servers are apparently unable * to handle referrals automatically, which causes a * <code>PartialResultException</code> to be thrown whenever a referral is * encountered in a search. To avoid this, set the * <code>ignorePartialResultException</code> property to <code>true</code>. * There is currently no way of manually handling these referrals in the form of * <code>ReferralException</code>, 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 * <code>PartialResultException</code> has been ignored (other than in the log). * * @see org.springframework.ldap.core.ContextSource * * @author Mattias Hellborg 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 boolean ignorePartialResultException = false; private boolean ignoreNameNotFoundException = 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; } /** * Get the ContextSource. * * @return the ContextSource. */ public ContextSource getContextSource() { return contextSource; } /** * Specify whether <code>NameNotFoundException</code> should be ignored in * searches. In previous version, <code>NameNotFoundException</code> caused * by the search base not being found was silently ignored. The default * behavior is now to treat this as an error (as it should), and to convert * and re-throw the exception. The ability to revert to the previous * behavior still exists. The only difference is that the incident is in * that case no longer silently ignored, but logged as a warning. * * @param ignore <code>true</code> if <code>NameNotFoundException</code> * should be ignored in searches, <code>false</code> otherwise. Default is * <code>false</code>. * * @since 1.3 */ public void setIgnoreNameNotFoundException(boolean ignore) { this.ignoreNameNotFoundException = ignore; } /** * Specify whether <code>PartialResultException</code> 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 * <code>PartialResultException</code> being thrown when a referral is * encountered by the server. Setting this property to <code>true</code> * presents a workaround to this problem by causing * <code>PartialResultException</code> to be ignored, so that the search * method returns normally. Default value of this parameter is * <code>false</code>. * * @param ignore <code>true</code> if <code>PartialResultException</code> * should be ignored in searches, <code>false</code> otherwise. Default is * <code>false</code>. */ public void setIgnorePartialResultException(boolean ignore) { this.ignorePartialResultException = ignore; } /* * @see * org.springframework.ldap.core.LdapOperations#search(javax.naming.Name, * java.lang.String, int, boolean, * org.springframework.ldap.core.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.core.LdapOperations#search(java.lang.String, * java.lang.String, int, boolean, * org.springframework.ldap.core.NameClassPairCallbackHandler) */ public void search(String base, String filter, int searchScope, boolean returningObjFlag, NameClassPairCallbackHandler handler) { search(base, filter, getDefaultSearchControls(searchScope, returningObjFlag, ALL_ATTRIBUTES), handler); } /* * @see * org.springframework.ldap.core.LdapOperations#search(javax.naming.Name, * java.lang.String, javax.naming.directory.SearchControls, * org.springframework.ldap.core.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 javax.naming.NamingException { return ctx.search(base, filter, controls); } }; if (handler instanceof ContextMapperCallbackHandler) { assureReturnObjFlagSet(controls); } search(se, handler); } /* * @see * org.springframework.ldap.core.LdapOperations#search(java.lang.String, * java.lang.String, javax.naming.directory.SearchControls, * org.springframework.ldap.core.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 javax.naming.NamingException { return ctx.search(base, filter, controls); } }; if (handler instanceof ContextMapperCallbackHandler) { assureReturnObjFlagSet(controls); } search(se, handler); } /* * @see * org.springframework.ldap.core.LdapOperations#search(javax.naming.Name, * java.lang.String, javax.naming.directory.SearchControls, * org.springframework.ldap.core.NameClassPairCallbackHandler, * org.springframework.ldap.core.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 javax.naming.NamingException { return ctx.search(base, filter, controls); } }; if (handler instanceof ContextMapperCallbackHandler) { assureReturnObjFlagSet(controls); } search(se, handler, processor); } /* * @see * org.springframework.ldap.core.LdapOperations#search(java.lang.String, * java.lang.String, javax.naming.directory.SearchControls, * org.springframework.ldap.core.NameClassPairCallbackHandler, * org.springframework.ldap.core.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 javax.naming.NamingException { return ctx.search(base, filter, controls); } }; if (handler instanceof ContextMapperCallbackHandler) { assureReturnObjFlagSet(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. * <p> * 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. * Must not be <code>null</code>. If no custom processing should take place, * please use e.g. * {@link #search(SearchExecutor, NameClassPairCallbackHandler)}. * @throws NamingException 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; RuntimeException ex = null; try { processor.preProcess(ctx); results = se.executeSearch(ctx); while (results.hasMore()) { NameClassPair result = (NameClassPair) results.next(); handler.handleNameClassPair(result); } } catch (NameNotFoundException e) { // It is possible to ignore errors caused by base not found if (ignoreNameNotFoundException) { log.warn("Base context not found, ignoring: " + e.getMessage()); } else { ex = LdapUtils.convertLdapException(e); } } catch (PartialResultException e) { // Workaround for AD servers not handling referrals correctly. if (ignorePartialResultException) { log.debug("PartialResultException encountered and ignored", e); } else { ex = LdapUtils.convertLdapException(e); } } catch (javax.naming.NamingException e) { ex = LdapUtils.convertLdapException(e); } finally { try { processor.postProcess(ctx); } catch (javax.naming.NamingException e) { if (ex == null) { ex = LdapUtils.convertLdapException(e); } else { // We already had an exception from above and should ignore // this one. log.debug("Ignoring Exception from postProcess, " + "main exception thrown instead", e); } } closeContextAndNamingEnumeration(ctx, results); // If we got an exception it should be thrown. if (ex != null) { throw ex; } } } /** * 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. * <p> * 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 NamingException 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.core.LdapOperations#search(javax.naming.Name, * java.lang.String, * org.springframework.ldap.core.NameClassPairCallbackHandler) */ public void search(Name base, String filter, NameClassPairCallbackHandler handler) { SearchControls controls = getDefaultSearchControls(DEFAULT_SEARCH_SCOPE, DONT_RETURN_OBJ_FLAG, ALL_ATTRIBUTES); if (handler instanceof ContextMapperCallbackHandler) { assureReturnObjFlagSet(controls); } search(base, filter, controls, handler); } /* * @see * org.springframework.ldap.core.LdapOperations#search(java.lang.String, * java.lang.String, * org.springframework.ldap.core.NameClassPairCallbackHandler) */ public void search(String base, String filter, NameClassPairCallbackHandler handler) { SearchControls controls = getDefaultSearchControls(DEFAULT_SEARCH_SCOPE, DONT_RETURN_OBJ_FLAG, ALL_ATTRIBUTES); if (handler instanceof ContextMapperCallbackHandler) { assureReturnObjFlagSet(controls); } search(base, filter, controls, handler); } /* * @see * org.springframework.ldap.core.LdapOperations#search(javax.naming.Name, * java.lang.String, int, java.lang.String[], * org.springframework.ldap.core.AttributesMapper) */ public List search(Name base, String filter, int searchScope, String[] attrs, AttributesMapper mapper) { return search(base, filter, getDefaultSearchControls(searchScope, DONT_RETURN_OBJ_FLAG, attrs), mapper); } /* * @see * org.springframework.ldap.core.LdapOperations#search(java.lang.String, * java.lang.String, int, java.lang.String[], * org.springframework.ldap.core.AttributesMapper) */ public List search(String base, String filter, int searchScope, String[] attrs, AttributesMapper mapper) { return search(base, filter, getDefaultSearchControls(searchScope, DONT_RETURN_OBJ_FLAG, attrs), mapper); } /* * @see * org.springframework.ldap.core.LdapOperations#search(javax.naming.Name, * java.lang.String, int, org.springframework.ldap.core.AttributesMapper) */ public List search(Name base, String filter, int searchScope, AttributesMapper mapper) { return search(base, filter, searchScope, ALL_ATTRIBUTES, mapper); } /* * @see * org.springframework.ldap.core.LdapOperations#search(java.lang.String, * java.lang.String, int, org.springframework.ldap.core.AttributesMapper) */ public List search(String base, String filter, int searchScope, AttributesMapper mapper) { return search(base, filter, searchScope, ALL_ATTRIBUTES, mapper); } /* * @see * org.springframework.ldap.core.LdapOperations#search(javax.naming.Name, * java.lang.String, org.springframework.ldap.core.AttributesMapper) */ public List search(Name base, String filter, AttributesMapper mapper) { return search(base, filter, DEFAULT_SEARCH_SCOPE, mapper); } /* * @see * org.springframework.ldap.core.LdapOperations#search(java.lang.String, * java.lang.String, org.springframework.ldap.core.AttributesMapper) */ public List search(String base, String filter, AttributesMapper mapper) { return search(base, filter, DEFAULT_SEARCH_SCOPE, mapper); } /* * @see * org.springframework.ldap.core.LdapOperations#search(javax.naming.Name, * java.lang.String, int, java.lang.String[], * org.springframework.ldap.core.ContextMapper) */ public List search(Name base, String filter, int searchScope, String[] attrs, ContextMapper mapper) { return search(base, filter, getDefaultSearchControls(searchScope, RETURN_OBJ_FLAG, attrs), mapper); } /* * @see * org.springframework.ldap.core.LdapOperations#search(java.lang.String, * java.lang.String, int, java.lang.String[], * org.springframework.ldap.core.ContextMapper) */ public List search(String base, String filter, int searchScope, String[] attrs, ContextMapper mapper) { return search(base, filter, getDefaultSearchControls(searchScope, RETURN_OBJ_FLAG, attrs), mapper); } /* * @see * org.springframework.ldap.core.LdapOperations#search(javax.naming.Name, * java.lang.String, int, org.springframework.ldap.core.ContextMapper) */ public List search(Name base, String filter, int searchScope, ContextMapper mapper) { return search(base, filter, searchScope, ALL_ATTRIBUTES, mapper); } /* * @see * org.springframework.ldap.core.LdapOperations#search(java.lang.String, * java.lang.String, int, org.springframework.ldap.core.ContextMapper) */ public List search(String base, String filter, int searchScope, ContextMapper mapper) { return search(base, filter, searchScope, ALL_ATTRIBUTES, mapper); } /* * @see * org.springframework.ldap.core.LdapOperations#search(javax.naming.Name, * java.lang.String, org.springframework.ldap.core.ContextMapper) */ public List search(Name base, String filter, ContextMapper mapper) { return search(base, filter, DEFAULT_SEARCH_SCOPE, mapper); } /* * @see * org.springframework.ldap.core.LdapOperations#search(java.lang.String, * java.lang.String, org.springframework.ldap.core.ContextMapper) */ public List search(String base, String filter, ContextMapper mapper) { return search(base, filter, DEFAULT_SEARCH_SCOPE, mapper); } /* * @see * org.springframework.ldap.core.LdapOperations#search(java.lang.String, * java.lang.String, javax.naming.directory.SearchControls, * org.springframework.ldap.core.ContextMapper) */ public List search(String base, String filter, SearchControls controls, ContextMapper mapper) { return search(base, filter, controls, mapper, new NullDirContextProcessor()); } /* * @see * org.springframework.ldap.core.LdapOperations#search(javax.naming.Name, * java.lang.String, javax.naming.directory.SearchControls, * org.springframework.ldap.core.ContextMapper) */ public List search(Name base, String filter, SearchControls controls, ContextMapper mapper) { return search(base, filter, controls, mapper, new NullDirContextProcessor()); } /* * @see * org.springframework.ldap.core.LdapOperations#search(javax.naming.Name, * java.lang.String, javax.naming.directory.SearchControls, * org.springframework.ldap.core.AttributesMapper) */ public List search(Name base, String filter, SearchControls controls, AttributesMapper mapper) { return search(base, filter, controls, mapper, new NullDirContextProcessor()); } /* * @see * org.springframework.ldap.core.LdapOperations#search(java.lang.String, * java.lang.String, javax.naming.directory.SearchControls, * org.springframework.ldap.core.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.core.LdapOperations#search(java.lang.String, * java.lang.String, javax.naming.directory.SearchControls, * org.springframework.ldap.core.AttributesMapper, * org.springframework.ldap.core.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.core.LdapOperations#search(javax.naming.Name, * java.lang.String, javax.naming.directory.SearchControls, * org.springframework.ldap.core.AttributesMapper, * org.springframework.ldap.core.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.core.LdapOperations#search(java.lang.String, * java.lang.String, javax.naming.directory.SearchControls, * org.springframework.ldap.core.ContextMapper, * org.springframework.ldap.core.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.core.LdapOperations#search(javax.naming.Name, * java.lang.String, javax.naming.directory.SearchControls, * org.springframework.ldap.core.ContextMapper, * org.springframework.ldap.core.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.core.LdapOperations#list(java.lang.String, * org.springframework.ldap.core.NameClassPairCallbackHandler) */ public void list(final String base, NameClassPairCallbackHandler handler) { SearchExecutor searchExecutor = new SearchExecutor() { public NamingEnumeration executeSearch(DirContext ctx) throws javax.naming.NamingException { return ctx.list(base); } }; search(searchExecutor, handler); } /* * @see org.springframework.ldap.core.LdapOperations#list(javax.naming.Name, * org.springframework.ldap.core.NameClassPairCallbackHandler) */ public void list(final Name base, NameClassPairCallbackHandler handler) { SearchExecutor searchExecutor = new SearchExecutor() { public NamingEnumeration executeSearch(DirContext ctx) throws javax.naming.NamingException { return ctx.list(base); } }; search(searchExecutor, handler); } /* * @see org.springframework.ldap.core.LdapOperations#list(java.lang.String, * org.springframework.ldap.core.NameClassPairMapper) */ public List list(String base, NameClassPairMapper mapper) { CollectingNameClassPairCallbackHandler handler = new MappingCollectingNameClassPairCallbackHandler(mapper); list(base, handler); return handler.getList(); } /* * @see org.springframework.ldap.core.LdapOperations#list(javax.naming.Name, * org.springframework.ldap.core.NameClassPairMapper) */ public List list(Name base, NameClassPairMapper mapper) { CollectingNameClassPairCallbackHandler handler = new MappingCollectingNameClassPairCallbackHandler(mapper); list(base, handler); return handler.getList(); } /* * @see org.springframework.ldap.core.LdapOperations#list(javax.naming.Name) */ public List list(final Name base) { return list(base, new DefaultNameClassPairMapper()); } /* * @see org.springframework.ldap.core.LdapOperations#list(java.lang.String) */ public List list(final String base) { return list(base, new DefaultNameClassPairMapper()); } /* * @see * org.springframework.ldap.core.LdapOperations#listBindings(java.lang.String * , org.springframework.ldap.core.NameClassPairCallbackHandler) */ public void listBindings(final String base, NameClassPairCallbackHandler handler) { SearchExecutor searchExecutor = new SearchExecutor() { public NamingEnumeration executeSearch(DirContext ctx) throws javax.naming.NamingException { return ctx.listBindings(base); } }; search(searchExecutor, handler); } /* * @see * org.springframework.ldap.core.LdapOperations#listBindings(javax.naming * .Name, org.springframework.ldap.core.NameClassPairCallbackHandler) */ public void listBindings(final Name base, NameClassPairCallbackHandler handler) { SearchExecutor searchExecutor = new SearchExecutor() { public NamingEnumeration executeSearch(DirContext ctx) throws javax.naming.NamingException { return ctx.listBindings(base); } }; search(searchExecutor, handler); } /* * @see * org.springframework.ldap.core.LdapOperations#listBindings(java.lang.String * , org.springframework.ldap.core.NameClassPairMapper) */ public List listBindings(String base, NameClassPairMapper mapper) { CollectingNameClassPairCallbackHandler handler = new MappingCollectingNameClassPairCallbackHandler(mapper); listBindings(base, handler); return handler.getList(); } /* * @see * org.springframework.ldap.core.LdapOperations#listBindings(javax.naming * .Name, org.springframework.ldap.core.NameClassPairMapper) */ public List listBindings(Name base, NameClassPairMapper mapper) { CollectingNameClassPairCallbackHandler handler = new MappingCollectingNameClassPairCallbackHandler(mapper); listBindings(base, handler); return handler.getList(); } /* * @see * org.springframework.ldap.core.LdapOperations#listBindings(java.lang.String * ) */ public List listBindings(final String base) { return listBindings(base, new DefaultNameClassPairMapper()); } /* * @see * org.springframework.ldap.core.LdapOperations#listBindings(javax.naming * .Name) */ public List listBindings(final Name base) { return listBindings(base, new DefaultNameClassPairMapper()); } /* * @see * org.springframework.ldap.core.LdapOperations#listBindings(java.lang.String * , org.springframework.ldap.core.ContextMapper) */ public List listBindings(String base, ContextMapper mapper) { ContextMapperCallbackHandler handler = new ContextMapperCallbackHandler(mapper); listBindings(base, handler); return handler.getList(); } /* * @see * org.springframework.ldap.core.LdapOperations#listBindings(javax.naming * .Name, org.springframework.ldap.core.ContextMapper) */ public List listBindings(Name base, ContextMapper mapper) { ContextMapperCallbackHandler handler = new ContextMapperCallbackHandler(mapper); listBindings(base, handler); return handler.getList(); } /* * @seeorg.springframework.ldap.core.LdapOperations#executeReadOnly(org. * springframework.ldap.core.DirContextProcessor) */ public Object executeReadOnly(ContextExecutor ce) { DirContext ctx = contextSource.getReadOnlyContext(); return executeWithContext(ce, ctx); } /* * @seeorg.springframework.ldap.core.LdapOperations#executeReadWrite(org. * springframework.ldap.core.DirContextProcessor) */ 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 (javax.naming.NamingException e) { throw LdapUtils.convertLdapException(e); } finally { closeContext(ctx); } } /* * @see * org.springframework.ldap.core.LdapOperations#lookup(javax.naming.Name) */ public Object lookup(final Name dn) { return executeReadOnly(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { return ctx.lookup(dn); } }); } /* * @see * org.springframework.ldap.core.LdapOperations#lookup(java.lang.String) */ public Object lookup(final String dn) { return executeReadOnly(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { return ctx.lookup(dn); } }); } /* * @see * org.springframework.ldap.core.LdapOperations#lookup(javax.naming.Name, * org.springframework.ldap.core.AttributesMapper) */ public Object lookup(final Name dn, final AttributesMapper mapper) { return executeReadOnly(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { Attributes attributes = ctx.getAttributes(dn); return mapper.mapFromAttributes(attributes); } }); } /* * @see * org.springframework.ldap.core.LdapOperations#lookup(java.lang.String, * org.springframework.ldap.core.AttributesMapper) */ public Object lookup(final String dn, final AttributesMapper mapper) { return executeReadOnly(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { Attributes attributes = ctx.getAttributes(dn); return mapper.mapFromAttributes(attributes); } }); } /* * @see * org.springframework.ldap.core.LdapOperations#lookup(javax.naming.Name, * org.springframework.ldap.core.ContextMapper) */ public Object lookup(final Name dn, final ContextMapper mapper) { return executeReadOnly(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { Object object = ctx.lookup(dn); return mapper.mapFromContext(object); } }); } /* * @see * org.springframework.ldap.core.LdapOperations#lookup(java.lang.String, * org.springframework.ldap.core.ContextMapper) */ public Object lookup(final String dn, final ContextMapper mapper) { return executeReadOnly(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { Object object = ctx.lookup(dn); return mapper.mapFromContext(object); } }); } /* * @see * org.springframework.ldap.core.LdapOperations#lookup(javax.naming.Name, * java.lang.String[], org.springframework.ldap.core.AttributesMapper) */ public Object lookup(final Name dn, final String[] attributes, final AttributesMapper mapper) { return executeReadOnly(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { Attributes filteredAttributes = ctx.getAttributes(dn, attributes); return mapper.mapFromAttributes(filteredAttributes); } }); } /* * @see * org.springframework.ldap.core.LdapOperations#lookup(java.lang.String, * java.lang.String[], org.springframework.ldap.core.AttributesMapper) */ public Object lookup(final String dn, final String[] attributes, final AttributesMapper mapper) { return executeReadOnly(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { Attributes filteredAttributes = ctx.getAttributes(dn, attributes); return mapper.mapFromAttributes(filteredAttributes); } }); } /* * @see * org.springframework.ldap.core.LdapOperations#lookup(javax.naming.Name, * java.lang.String[], org.springframework.ldap.core.ContextMapper) */ public Object lookup(final Name dn, final String[] attributes, final ContextMapper mapper) { return executeReadOnly(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { Attributes filteredAttributes = ctx.getAttributes(dn, attributes); DirContextAdapter contextAdapter = new DirContextAdapter(filteredAttributes, dn); return mapper.mapFromContext(contextAdapter); } }); } /* * @see * org.springframework.ldap.core.LdapOperations#lookup(java.lang.String, * java.lang.String[], org.springframework.ldap.core.ContextMapper) */ public Object lookup(final String dn, final String[] attributes, final ContextMapper mapper) { return executeReadOnly(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.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.core.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 javax.naming.NamingException { ctx.modifyAttributes(dn, mods); return null; } }); } /* * @see * org.springframework.ldap.core.LdapOperations#modifyAttributes(java.lang * .String, javax.naming.directory.ModificationItem[]) */ public void modifyAttributes(final String dn, final ModificationItem[] mods) { executeReadWrite(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { ctx.modifyAttributes(dn, mods); return null; } }); } /* * @see org.springframework.ldap.core.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 javax.naming.NamingException { ctx.bind(dn, obj, attributes); return null; } }); } /* * @see org.springframework.ldap.core.LdapOperations#bind(java.lang.String, * java.lang.Object, javax.naming.directory.Attributes) */ public void bind(final String dn, final Object obj, final Attributes attributes) { executeReadWrite(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { ctx.bind(dn, obj, attributes); return null; } }); } /* * @see * org.springframework.ldap.core.LdapOperations#unbind(javax.naming.Name) */ public void unbind(final Name dn) { doUnbind(dn); } /* * @see * org.springframework.ldap.core.LdapOperations#unbind(java.lang.String) */ public void unbind(final String dn) { doUnbind(dn); } /* * @see * org.springframework.ldap.core.LdapOperations#unbind(javax.naming.Name, * boolean) */ public void unbind(final Name dn, boolean recursive) { if (!recursive) { doUnbind(dn); } else { doUnbindRecursively(dn); } } /* * @see * org.springframework.ldap.core.LdapOperations#unbind(java.lang.String, * boolean) */ public void unbind(final String dn, boolean recursive) { if (!recursive) { doUnbind(dn); } else { doUnbindRecursively(dn); } } private void doUnbind(final Name dn) { executeReadWrite(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { ctx.unbind(dn); return null; } }); } private void doUnbind(final String dn) { executeReadWrite(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { ctx.unbind(dn); return null; } }); } private void doUnbindRecursively(final Name dn) { executeReadWrite(new ContextExecutor() { public Object executeWithContext(DirContext ctx) { deleteRecursively(ctx, new DistinguishedName(dn)); return null; } }); } private void doUnbindRecursively(final String dn) { executeReadWrite(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.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 NamingException if any error occurs */ protected void deleteRecursively(DirContext ctx, DistinguishedName name) { 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 (javax.naming.NamingException e) { throw LdapUtils.convertLdapException(e); } finally { try { enumeration.close(); } catch (Exception e) { // Never mind this } } } /* * @see * org.springframework.ldap.core.LdapOperations#rebind(javax.naming.Name, * java.lang.Object, javax.naming.directory.Attributes) */ public void rebind(final Name dn, final Object obj, final Attributes attributes) { executeReadWrite(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { ctx.rebind(dn, obj, attributes); return null; } }); } /* * @see * org.springframework.ldap.core.LdapOperations#rebind(java.lang.String, * java.lang.Object, javax.naming.directory.Attributes) */ public void rebind(final String dn, final Object obj, final Attributes attributes) { executeReadWrite(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { ctx.rebind(dn, obj, attributes); return null; } }); } /* * @see * org.springframework.ldap.core.LdapOperations#rename(javax.naming.Name, * javax.naming.Name) */ public void rename(final Name oldDn, final Name newDn) { executeReadWrite(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { ctx.rename(oldDn, newDn); return null; } }); } /* * @see * org.springframework.ldap.core.LdapOperations#rename(java.lang.String, * java.lang.String) */ public void rename(final String oldDn, final String newDn) { executeReadWrite(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.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. } } } 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 static 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 Hellborg Arthursson */ public final static class MappingCollectingNameClassPairCallbackHandler extends CollectingNameClassPairCallbackHandler { private NameClassPairMapper mapper; public MappingCollectingNameClassPairCallbackHandler(NameClassPairMapper mapper) { this.mapper = mapper; } /* * @seeorg.springframework.ldap.CollectingNameClassPairCallbackHandler# * getObjectFromNameClassPair(javax.naming.NameClassPair) */ public Object getObjectFromNameClassPair(NameClassPair nameClassPair) { try { return mapper.mapFromNameClassPair(nameClassPair); } catch (javax.naming.NamingException e) { throw LdapUtils.convertLdapException(e); } } } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.LdapOperations#lookupContext(javax.naming * .Name) */ public DirContextOperations lookupContext(Name dn) { return (DirContextOperations) lookup(dn); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.LdapOperations#lookupContext(java.lang. * String) */ public DirContextOperations lookupContext(String dn) { return (DirContextOperations) lookup(dn); } /* * (non-Javadoc) * * @seeorg.springframework.ldap.core.LdapOperations#modifyAttributes(org. * springframework.ldap.core.DirContextOperations) */ 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."); } } /* * (non-Javadoc) * * @seeorg.springframework.ldap.core.LdapOperations#bind(org. * springframework.ldap.core.DirContextOperations) */ public void bind(DirContextOperations ctx) { Name dn = ctx.getDn(); if (dn != null && !ctx.isUpdateMode()) { bind(dn, ctx, null); } else { throw new IllegalStateException("The DirContextOperations instance needs to be properly initialized."); } } /* * @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) * * @see * org.springframework.ldap.core.LdapOperations#authenticate(javax.naming * .Name, java.lang.String, java.lang.String) */ public boolean authenticate(Name base, String filter, String password) { return authenticate(base, filter, password, new NullAuthenticatedLdapEntryContextCallback(), new NullAuthenticationErrorCallback()); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.LdapOperations#authenticate(java.lang.String * , java.lang.String, java.lang.String) */ public boolean authenticate(String base, String filter, String password) { return authenticate(new DistinguishedName(base), filter, password, new NullAuthenticatedLdapEntryContextCallback(), new NullAuthenticationErrorCallback()); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.LdapOperations#authenticate(java.lang.String * , java.lang.String, java.lang.String, * org.springframework.ldap.core.AuthenticatedLdapEntryContextCallback) */ public boolean authenticate(String base, String filter, String password, AuthenticatedLdapEntryContextCallback callback) { return authenticate(new DistinguishedName(base), filter, password, callback, new NullAuthenticationErrorCallback()); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.LdapOperations#authenticate(javax.naming * .Name, java.lang.String, java.lang.String, * org.springframework.ldap.core.AuthenticatedLdapEntryContextCallback) */ public boolean authenticate(Name base, String filter, String password, final AuthenticatedLdapEntryContextCallback callback) { return authenticate(base, filter, password, callback, new NullAuthenticationErrorCallback()); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.LdapOperations#authenticate(java.lang.String * , java.lang.String, java.lang.String, * org.springframework.ldap.core.AuthenticationErrorCallback) */ public boolean authenticate(String base, String filter, String password, AuthenticationErrorCallback errorCallback) { return authenticate(new DistinguishedName(base), filter, password, new NullAuthenticatedLdapEntryContextCallback(), errorCallback); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.LdapOperations#authenticate(javax.naming * .Name, java.lang.String, java.lang.String, * org.springframework.ldap.core.AuthenticationErrorCallback) */ public boolean authenticate(Name base, String filter, String password, final AuthenticationErrorCallback errorCallback) { return authenticate(base, filter, password, new NullAuthenticatedLdapEntryContextCallback(), errorCallback); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.LdapOperations#authenticate(java.lang.String * , java.lang.String, java.lang.String, * org.springframework.ldap.core.AuthenticatedLdapEntryContextCallback, * org.springframework.ldap.core.AuthenticationErrorCallback) */ public boolean authenticate(String base, String filter, String password, final AuthenticatedLdapEntryContextCallback callback, final AuthenticationErrorCallback errorCallback) { return authenticate(new DistinguishedName(base), filter, password, callback, errorCallback); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.LdapOperations#authenticate(javax.naming * .Name, java.lang.String, java.lang.String, * org.springframework.ldap.core.AuthenticatedLdapEntryContextCallback, * org.springframework.ldap.core.AuthenticationErrorCallback) */ public boolean authenticate(Name base, String filter, String password, final AuthenticatedLdapEntryContextCallback callback, final AuthenticationErrorCallback errorCallback) { List result = search(base, filter, new LdapEntryIdentificationContextMapper()); if (result.size() == 0) { String msg = "No results found for search, base: '" + base + "'; filter: '" + filter + "'."; log.info(msg); return false; } else if (result.size() > 1) { String msg = "base: '" + base + "'; filter: '" + filter + "'."; throw new IncorrectResultSizeDataAccessException(msg, 1, result.size()); } final LdapEntryIdentification entryIdentification = (LdapEntryIdentification) result.get(0); try { DirContext ctx = contextSource.getContext(entryIdentification.getAbsoluteDn().toString(), password); executeWithContext(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws javax.naming.NamingException { callback.executeWithContext(ctx, entryIdentification); return null; } }, ctx); return true; } catch (Exception e) { log.info("Authentication failed for entry with DN '" + entryIdentification.getAbsoluteDn() + "'", e); errorCallback.execute(e); return false; } } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.LdapOperations#searchForObject(javax.naming * .Name, java.lang.String, org.springframework.ldap.core.ContextMapper) */ public Object searchForObject(Name base, String filter, ContextMapper mapper) { List result = search(base, filter, mapper); if (result.size() == 0) { throw new EmptyResultDataAccessException(1); } else if (result.size() != 1) { throw new IncorrectResultSizeDataAccessException(1, result.size()); } return result.get(0); } /* * (non-Javadoc) * * @see * org.springframework.ldap.core.LdapOperations#searchForObject(java.lang * .String, java.lang.String, org.springframework.ldap.core.ContextMapper) */ public Object searchForObject(String base, String filter, ContextMapper mapper) { return searchForObject(new DistinguishedName(base), filter, mapper); } private static final class NullAuthenticatedLdapEntryContextCallback implements AuthenticatedLdapEntryContextCallback { public void executeWithContext(DirContext ctx, LdapEntryIdentification ldapEntryIdentification) { // Do nothing } } private static final class NullAuthenticationErrorCallback implements AuthenticationErrorCallback { public void execute(Exception e) { // Do nothing } } }