|  | @@ -20,6 +20,11 @@ import org.springframework.dao.IncorrectResultSizeDataAccessException;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  import org.springframework.util.Assert;
 | 
	
		
			
				|  |  |  import org.springframework.util.StringUtils;
 | 
	
		
			
				|  |  | +import org.springframework.ldap.ContextSource;
 | 
	
		
			
				|  |  | +import org.springframework.ldap.ContextExecutor;
 | 
	
		
			
				|  |  | +import org.springframework.ldap.ContextMapper;
 | 
	
		
			
				|  |  | +import org.springframework.ldap.support.DirContextAdapter;
 | 
	
		
			
				|  |  | +import org.springframework.ldap.support.DistinguishedName;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  import java.util.HashSet;
 | 
	
		
			
				|  |  |  import java.util.Set;
 | 
	
	
		
			
				|  | @@ -36,52 +41,35 @@ import javax.naming.directory.SearchResult;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /**
 | 
	
		
			
				|  |  | - * LDAP equivalent of the Spring JdbcTemplate class.<p>This is mainly intended to simplify Ldap access within Acegi
 | 
	
		
			
				|  |  | - * Security's LDAP-related services.</p>
 | 
	
		
			
				|  |  | + * LDAP equivalent of the Spring JdbcTemplate class.
 | 
	
		
			
				|  |  | + * <p>
 | 
	
		
			
				|  |  | + * This is mainly intended to simplify Ldap access within Acegi Security's LDAP-related services.
 | 
	
		
			
				|  |  | + * </p>
 | 
	
		
			
				|  |  |   *
 | 
	
		
			
				|  |  |   * @author Ben Alex
 | 
	
		
			
				|  |  |   * @author Luke Taylor
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  | -public class LdapTemplate {
 | 
	
		
			
				|  |  | +public class LdapTemplate extends org.springframework.ldap.LdapTemplate {
 | 
	
		
			
				|  |  |      //~ Static fields/initializers =====================================================================================
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      public static final String[] NO_ATTRS = new String[0];
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      //~ Instance fields ================================================================================================
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    private InitialDirContextFactory dirContextFactory;
 | 
	
		
			
				|  |  |      private NamingExceptionTranslator exceptionTranslator = new LdapExceptionTranslator();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /** Default search controls */
 | 
	
		
			
				|  |  |      private SearchControls searchControls = new SearchControls();
 | 
	
		
			
				|  |  | -    private String password = null;
 | 
	
		
			
				|  |  | -    private String principalDn = null;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      //~ Constructors ===================================================================================================
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    public LdapTemplate(InitialDirContextFactory dirContextFactory) {
 | 
	
		
			
				|  |  | -        Assert.notNull(dirContextFactory, "An InitialDirContextFactory is required");
 | 
	
		
			
				|  |  | -        this.dirContextFactory = dirContextFactory;
 | 
	
		
			
				|  |  | +    public LdapTemplate(ContextSource contextSource) {
 | 
	
		
			
				|  |  | +        Assert.notNull(contextSource, "ContextSource cannot be null");
 | 
	
		
			
				|  |  | +        setContextSource(contextSource);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | -     *
 | 
	
		
			
				|  |  | -     * @param dirContextFactory the source of DirContexts
 | 
	
		
			
				|  |  | -     * @param userDn the user name to authenticate as when obtaining new contexts
 | 
	
		
			
				|  |  | -     * @param password the user's password
 | 
	
		
			
				|  |  | -     */
 | 
	
		
			
				|  |  | -    public LdapTemplate(InitialDirContextFactory dirContextFactory, String userDn, String password) {
 | 
	
		
			
				|  |  | -        this(dirContextFactory);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        Assert.hasLength(userDn, "userDn must not be null or empty");
 | 
	
		
			
				|  |  | -        Assert.notNull(password, "password cannot be null");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        this.principalDn = userDn;
 | 
	
		
			
				|  |  | -        this.password = password;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |      //~ Methods ========================================================================================================
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /**
 | 
	
	
		
			
				|  | @@ -96,9 +84,9 @@ public class LdapTemplate {
 | 
	
		
			
				|  |  |      public boolean compare(final String dn, final String attributeName, final Object value) {
 | 
	
		
			
				|  |  |          final String comparisonFilter = "(" + attributeName + "={0})";
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        class LdapCompareCallback implements LdapCallback {
 | 
	
		
			
				|  |  | -            public Object doInDirContext(DirContext ctx)
 | 
	
		
			
				|  |  | -                throws NamingException {
 | 
	
		
			
				|  |  | +        class LdapCompareCallback implements ContextExecutor {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            public Object executeWithContext(DirContext ctx) throws NamingException {
 | 
	
		
			
				|  |  |                  SearchControls ctls = new SearchControls();
 | 
	
		
			
				|  |  |                  ctls.setReturningAttributes(NO_ATTRS);
 | 
	
		
			
				|  |  |                  ctls.setSearchScope(SearchControls.OBJECT_SCOPE);
 | 
	
	
		
			
				|  | @@ -111,30 +99,28 @@ public class LdapTemplate {
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        Boolean matches = (Boolean) execute(new LdapCompareCallback());
 | 
	
		
			
				|  |  | +        Boolean matches = (Boolean) executeReadOnly(new LdapCompareCallback());
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          return matches.booleanValue();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    public Object execute(LdapCallback callback) throws DataAccessException {
 | 
	
		
			
				|  |  | -        DirContext ctx = null;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        try {
 | 
	
		
			
				|  |  | -            ctx = (principalDn == null) ? dirContextFactory.newInitialDirContext()
 | 
	
		
			
				|  |  | -                                        : dirContextFactory.newInitialDirContext(principalDn, password);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            return callback.doInDirContext(ctx);
 | 
	
		
			
				|  |  | -        } catch (NamingException exception) {
 | 
	
		
			
				|  |  | -            throw exceptionTranslator.translate("LdapCallback", exception);
 | 
	
		
			
				|  |  | -        } finally {
 | 
	
		
			
				|  |  | -            LdapUtils.closeContext(ctx);
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | +//    public Object execute(LdapCallback callback) throws DataAccessException {
 | 
	
		
			
				|  |  | +//        DirContext ctx = null;
 | 
	
		
			
				|  |  | +//
 | 
	
		
			
				|  |  | +//        try {
 | 
	
		
			
				|  |  | +//            ctx = dirContextFactory.getReadOnlyContext();
 | 
	
		
			
				|  |  | +//
 | 
	
		
			
				|  |  | +//            return callback.doInDirContext(ctx);
 | 
	
		
			
				|  |  | +//        } catch (NamingException exception) {
 | 
	
		
			
				|  |  | +//            throw exceptionTranslator.translate("LdapCallback", exception);
 | 
	
		
			
				|  |  | +//        } finally {
 | 
	
		
			
				|  |  | +//            LdapUtils.closeContext(ctx);
 | 
	
		
			
				|  |  | +//        }
 | 
	
		
			
				|  |  | +//    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      public boolean nameExists(final String dn) {
 | 
	
		
			
				|  |  | -        Boolean exists = (Boolean) execute(new LdapCallback() {
 | 
	
		
			
				|  |  | -                public Object doInDirContext(DirContext ctx)
 | 
	
		
			
				|  |  | -                    throws NamingException {
 | 
	
		
			
				|  |  | +        Boolean exists = (Boolean) executeReadOnly(new ContextExecutor() {
 | 
	
		
			
				|  |  | +                public Object executeWithContext(DirContext ctx) throws NamingException {
 | 
	
		
			
				|  |  |                      try {
 | 
	
		
			
				|  |  |                          Object obj = ctx.lookup(LdapUtils.getRelativeName(dn, ctx));
 | 
	
		
			
				|  |  |                          if (obj instanceof Context) {
 | 
	
	
		
			
				|  | @@ -161,12 +147,17 @@ public class LdapTemplate {
 | 
	
		
			
				|  |  |       *
 | 
	
		
			
				|  |  |       * @return the object created by the mapper
 | 
	
		
			
				|  |  |       */
 | 
	
		
			
				|  |  | -    public Object retrieveEntry(final String dn, final LdapEntryMapper mapper, final String[] attributesToRetrieve) {
 | 
	
		
			
				|  |  | -        return execute(new LdapCallback() {
 | 
	
		
			
				|  |  | -                public Object doInDirContext(DirContext ctx)
 | 
	
		
			
				|  |  | -                    throws NamingException {
 | 
	
		
			
				|  |  | -                    return mapper.mapAttributes(dn,
 | 
	
		
			
				|  |  | -                        ctx.getAttributes(LdapUtils.getRelativeName(dn, ctx), attributesToRetrieve));
 | 
	
		
			
				|  |  | +    public Object retrieveEntry(final String dn, final ContextMapper mapper, final String[] attributesToRetrieve) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        return executeReadOnly(new ContextExecutor() {
 | 
	
		
			
				|  |  | +                public Object executeWithContext(DirContext ctx) throws NamingException {
 | 
	
		
			
				|  |  | +                    Attributes attrs = ctx.getAttributes(LdapUtils.getRelativeName(dn, ctx), attributesToRetrieve);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    // Object object = ctx.lookup(LdapUtils.getRelativeName(dn, ctx));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    DirContextAdapter ctxAdapter = new DirContextAdapter(attrs, new DistinguishedName(dn));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    return mapper.mapFromContext(ctxAdapter);
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              });
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -185,8 +176,8 @@ public class LdapTemplate {
 | 
	
		
			
				|  |  |       */
 | 
	
		
			
				|  |  |      public Set searchForSingleAttributeValues(final String base, final String filter, final Object[] params,
 | 
	
		
			
				|  |  |          final String attributeName) {
 | 
	
		
			
				|  |  | -        class SingleAttributeSearchCallback implements LdapCallback {
 | 
	
		
			
				|  |  | -            public Object doInDirContext(DirContext ctx)
 | 
	
		
			
				|  |  | +        class SingleAttributeSearchCallback implements ContextExecutor {
 | 
	
		
			
				|  |  | +            public Object executeWithContext(DirContext ctx)
 | 
	
		
			
				|  |  |                  throws NamingException {
 | 
	
		
			
				|  |  |                  Set unionOfValues = new HashSet();
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -224,7 +215,7 @@ public class LdapTemplate {
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        return (Set) execute(new SingleAttributeSearchCallback());
 | 
	
		
			
				|  |  | +        return (Set) executeReadOnly(new SingleAttributeSearchCallback());
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      /**
 | 
	
	
		
			
				|  | @@ -242,10 +233,12 @@ public class LdapTemplate {
 | 
	
		
			
				|  |  |       *         result.
 | 
	
		
			
				|  |  |       */
 | 
	
		
			
				|  |  |      public Object searchForSingleEntry(final String base, final String filter, final Object[] params,
 | 
	
		
			
				|  |  | -        final LdapEntryMapper mapper) {
 | 
	
		
			
				|  |  | -        return execute(new LdapCallback() {
 | 
	
		
			
				|  |  | -                public Object doInDirContext(DirContext ctx)
 | 
	
		
			
				|  |  | +        final ContextMapper mapper) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        return executeReadOnly(new ContextExecutor() {
 | 
	
		
			
				|  |  | +                public Object executeWithContext(DirContext ctx)
 | 
	
		
			
				|  |  |                      throws NamingException {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |                      NamingEnumeration results = ctx.search(base, filter, params, searchControls);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                      if (!results.hasMore()) {
 | 
	
	
		
			
				|  | @@ -274,7 +267,10 @@ public class LdapTemplate {
 | 
	
		
			
				|  |  |                          dn.append(nameInNamespace);
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                    return mapper.mapAttributes(dn.toString(), searchResult.getAttributes());
 | 
	
		
			
				|  |  | +                    DirContextAdapter ctxAdapter = new DirContextAdapter(
 | 
	
		
			
				|  |  | +                            searchResult.getAttributes(), new DistinguishedName(dn.toString()));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    return mapper.mapFromContext(ctxAdapter);
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              });
 | 
	
		
			
				|  |  |      }
 |