public Rdn[] findUserRDN( String username ) throws Exception
    {
        if ( userDNCache != null )
        {
            // Return a cache entry if one exists.
            final CacheableOptional<DNCacheEntry> dnCacheEntry = userDNCache.get( username );
            if ( dnCacheEntry != null )
            {
                if (dnCacheEntry.isAbsent()) {
                    throw new UserNotFoundException( "User '" + username + "' not found (negative lookup cache result)");
                } else {
                    return dnCacheEntry.get().getUserRDN();
                }
            }
        }

        // No cache entry. Query for the value, and add that to the cache.
        try
        {
            final Rdn[] userRDN = findUserRDN( username, baseDN );
            if ( userDNCache != null )
            {
                userDNCache.put( username, CacheableOptional.of(new DNCacheEntry( userRDN, baseDN )) );
            }
            return userRDN;
        }
        catch ( Exception e )
        {
            try {
                if (alternateBaseDN != null) {
                    final Rdn[] userRDN = findUserRDN(username, alternateBaseDN);
                    if (userDNCache != null) {
                        userDNCache.put(username, CacheableOptional.of(new DNCacheEntry(userRDN, alternateBaseDN)));
                    }
                    return userRDN;
                } else {
                    throw e;
                }
            } catch ( UserNotFoundException ex ) {
                if (userDNCache != null) {
                    // Cache the 'not found' event to prevent incurring costs for future lookups (that will be equally unsuccessful). OF-2170
                    userDNCache.put(username, CacheableOptional.of(null));
                }
                throw ex;
            }
        }
    }
Finds a user's RDN using their username. Normally, this search will
be performed using the field "uid", but this can be changed by setting
the {@code usernameField} property.<p>

Searches are performed over all subtrees relative to the {@code baseDN}.
If the search fails in the {@code baseDN} then another search will be
performed in the {@code alternateBaseDN}. For example, if the {@code baseDN}
is "o=jivesoftware, o=com" and we do a search for "mtucker", then we might
find a userDN of "uid=mtucker,ou=People". This kind of searching is a good
thing since it doesn't make the assumption that all user records are stored
in a flat structure. However, it does add the requirement that "uid" field
(or the other field specified) must be unique over the entire subtree from
the {@code baseDN}. For example, it's entirely possible to create two dn's
in your LDAP directory with the same uid: "uid=mtucker,ou=People" and
"uid=mtucker,ou=Administrators". In such a case, it's not possible to
uniquely identify a user, so this method will throw an error.<p>

The dn that's returned is relative to the default {@code baseDN}.

@param username the username to lookup the dn for.
@return the dn associated with {@code username}.
@throws Exception if the search for the dn fails.
xmppserver/src/main/java/org/jivesoftware/openfire/ldap/LdapManager.java