LDAP: move galLookup to DavExchangeSession

git-svn-id: http://svn.code.sf.net/p/davmail/code/trunk@1333 3d1905a2-6b24-0410-a738-b14d5a86fcbd
This commit is contained in:
mguessan 2010-08-09 22:19:15 +00:00
parent 905870f7da
commit 3d98a34328
6 changed files with 119 additions and 98 deletions

View File

@ -118,7 +118,6 @@ public abstract class ExchangeSession {
private final String userName;
private boolean disableGalLookup;
protected static final String YYYY_MM_DD_HH_MM_SS = "yyyy/MM/dd HH:mm:ss";
private static final String YYYYMMDD_T_HHMMSS_Z = "yyyyMMdd'T'HHmmss'Z'";
protected static final String YYYY_MM_DD_T_HHMMSS_Z = "yyyy-MM-dd'T'HH:mm:ss'Z'";
@ -2816,7 +2815,7 @@ public abstract class ExchangeSession {
return results;
}
public abstract Map<String, Contact> galFind(Condition condition) throws IOException;
public abstract Map<String, Contact> galFind(Condition condition, Set<String> returningAttributes, int sizeLimit) throws IOException;
/**
* Full Contact attribute list
@ -2890,39 +2889,6 @@ public abstract class ExchangeSession {
CONTACT_ATTRIBUTES.add("fburl");
}
/**
* Get extended address book information for person with gallookup.
* Does not work with Exchange 2007
*
* @param person person attributes map
*/
public void galLookup(Map<String, String> person) {
if (!disableGalLookup) {
GetMethod getMethod = null;
try {
getMethod = new GetMethod(URIUtil.encodePathQuery(getCmdBasePath() + "?Cmd=gallookup&ADDR=" + person.get("EM")));
DavGatewayHttpClientFacade.executeGetMethod(httpClient, getMethod, true);
Map<String, Map<String, String>> results = XMLStreamUtil.getElementContentsAsMap(getMethod.getResponseBodyAsStream(), "person", "alias");
// add detailed information
if (!results.isEmpty()) {
Map<String, String> fullperson = results.get(person.get("AN").toLowerCase());
if (fullperson != null) {
for (Map.Entry<String, String> entry : fullperson.entrySet()) {
person.put(entry.getKey(), entry.getValue());
}
}
}
} catch (IOException e) {
LOGGER.warn("Unable to gallookup person: " + person + ", disable GalLookup");
disableGalLookup = true;
} finally {
if (getMethod != null) {
getMethod.releaseConnection();
}
}
}
}
/**
* Get freebusy data string from Exchange.
*

View File

@ -198,6 +198,20 @@ public class DavExchangeSession extends ExchangeSession {
GALFIND_CRITERIA_MAP.put("apple-group-realname", "DP");
}
static final HashSet<String> GALLOOKUP_ATTRIBUTES = new HashSet<String>();
static {
GALLOOKUP_ATTRIBUTES.add("givenname");
GALLOOKUP_ATTRIBUTES.add("initials");
GALLOOKUP_ATTRIBUTES.add("sn");
GALLOOKUP_ATTRIBUTES.add("street");
GALLOOKUP_ATTRIBUTES.add("st");
GALLOOKUP_ATTRIBUTES.add("postalcode");
GALLOOKUP_ATTRIBUTES.add("c");
GALLOOKUP_ATTRIBUTES.add("departement");
GALLOOKUP_ATTRIBUTES.add("mobile");
}
/**
* Exchange to LDAP attribute map
*/
@ -225,7 +239,7 @@ public class DavExchangeSession extends ExchangeSession {
}
@Override
public Map<String, ExchangeSession.Contact> galFind(Condition condition) throws IOException {
public Map<String, ExchangeSession.Contact> galFind(Condition condition, Set<String> returningAttributes, int sizeLimit) throws IOException {
Map<String, ExchangeSession.Contact> contacts = new HashMap<String, ExchangeSession.Contact>();
if (condition instanceof MultiCondition) {
// TODO
@ -242,9 +256,15 @@ public class DavExchangeSession extends ExchangeSession {
getMethod.releaseConnection();
}
LOGGER.debug("galfind " + searchAttribute + '=' + searchValue + ": " + results.size() + " result(s)");
for (Map<String, String> result:results.values()) {
Contact contact = buildGalfindContact(result);
for (Map<String, String> result : results.values()) {
Contact contact = new Contact();
contact.setName(result.get("AN"));
contact.put("uid", result.get("AN"));
buildGalfindContact(contact, result);
if (condition.isMatch(contact)) {
if (needGalLookup(returningAttributes)) {
galLookup(contact);
}
contacts.put(contact.getName().toLowerCase(), contact);
}
}
@ -254,17 +274,63 @@ public class DavExchangeSession extends ExchangeSession {
return contacts;
}
protected Contact buildGalfindContact(Map<String, String> response) {
Contact contact = new Contact();
contact.setName(response.get("AN"));
contact.put("uid", response.get("AN"));
protected boolean needGalLookup(Set<String> returningAttributes) {
// iCal search, do not call gallookup
if (returningAttributes.contains("apple-serviceslocator")) {
return false;
// return all attributes => call gallookup
} else if (returningAttributes.isEmpty()) {
return true;
}
for (String attributeName : GALLOOKUP_ATTRIBUTES) {
if (returningAttributes.contains(attributeName)) {
return true;
}
}
return false;
}
private boolean disableGalLookup;
/**
* Get extended address book information for person with gallookup.
* Does not work with Exchange 2007
*
* @param contact galfind contact
*/
public void galLookup(Contact contact) {
if (!disableGalLookup) {
GetMethod getMethod = null;
try {
getMethod = new GetMethod(URIUtil.encodePathQuery(getCmdBasePath() + "?Cmd=gallookup&ADDR=" + contact.get("smtpemail1")));
DavGatewayHttpClientFacade.executeGetMethod(httpClient, getMethod, true);
Map<String, Map<String, String>> results = XMLStreamUtil.getElementContentsAsMap(getMethod.getResponseBodyAsStream(), "person", "alias");
// add detailed information
if (!results.isEmpty()) {
Map<String, String> personGalLookupDetails = results.get(contact.get("uid").toLowerCase());
if (personGalLookupDetails != null) {
buildGalfindContact(contact, personGalLookupDetails);
}
}
} catch (IOException e) {
LOGGER.warn("Unable to gallookup person: " + contact + ", disable GalLookup");
disableGalLookup = true;
} finally {
if (getMethod != null) {
getMethod.releaseConnection();
}
}
}
}
protected void buildGalfindContact(Contact contact, Map<String, String> response) {
for (Map.Entry<String, String> entry : GALFIND_ATTRIBUTE_MAP.entrySet()) {
String attributeValue = response.get(entry.getValue());
if (attributeValue != null) {
contact.put(entry.getKey(), attributeValue);
}
}
return contact;
}
@Override
@ -528,6 +594,15 @@ public class DavExchangeSession extends ExchangeSession {
}
if ("urlcompname".equals(field.alias)) {
buffer.append(StringUtil.encodeUrlcompname(value));
} else if (field.isIntValue()) {
// check value
try {
Integer.parseInt(value);
buffer.append(value);
} catch (NumberFormatException e) {
// invalid value, replace with 0
buffer.append('0');
}
} else {
buffer.append(value);
}

View File

@ -1280,17 +1280,17 @@ public class EwsExchangeSession extends ExchangeSession {
return contact;
}
public Map<String, ExchangeSession.Contact> galFind(Condition condition) throws IOException {
public Map<String, ExchangeSession.Contact> galFind(Condition condition, Set<String> returningAttributes, int sizeLimit) throws IOException {
Map<String, ExchangeSession.Contact> contacts = new HashMap<String, ExchangeSession.Contact>();
if (condition instanceof MultiCondition) {
List<Condition> conditions = ((MultiCondition) condition).getConditions();
Operator operator = ((MultiCondition) condition).getOperator();
if (operator == Operator.Or) {
for (Condition innerCondition : conditions) {
contacts.putAll(galFind(innerCondition));
contacts.putAll(galFind(innerCondition, returningAttributes, sizeLimit));
}
} else if (operator == Operator.And && !conditions.isEmpty()) {
Map<String, ExchangeSession.Contact> innerContacts = galFind(conditions.get(0));
Map<String, ExchangeSession.Contact> innerContacts = galFind(conditions.get(0), returningAttributes, sizeLimit);
for (ExchangeSession.Contact contact : innerContacts.values()) {
if (condition.isMatch(contact)) {
contacts.put(contact.getName().toLowerCase(), contact);

View File

@ -186,20 +186,6 @@ public class LdapConnection extends AbstractConnection {
STATIC_ATTRIBUTE_MAP.put("apple-serviceslocator", COMPUTER_GUID + ':' + VIRTUALHOST_GUID + ":calendar");
}
static final HashSet<String> EXTENDED_ATTRIBUTES = new HashSet<String>();
static {
EXTENDED_ATTRIBUTES.add("givenname");
EXTENDED_ATTRIBUTES.add("initials");
EXTENDED_ATTRIBUTES.add("sn");
EXTENDED_ATTRIBUTES.add("street");
EXTENDED_ATTRIBUTES.add("st");
EXTENDED_ATTRIBUTES.add("postalcode");
EXTENDED_ATTRIBUTES.add("c");
EXTENDED_ATTRIBUTES.add("departement");
EXTENDED_ATTRIBUTES.add("mobile");
}
/**
* LDAP to Exchange Criteria Map
*/
@ -846,7 +832,7 @@ public class LdapConnection extends AbstractConnection {
static interface LdapFilter {
ExchangeSession.Condition getContactSearchFilter();
Map<String, ExchangeSession.Contact> findInGAL(ExchangeSession session) throws IOException;
Map<String, ExchangeSession.Contact> findInGAL(ExchangeSession session, Set<String> returningAttributes, int sizeLimit) throws IOException;
void add(LdapFilter filter);
@ -973,11 +959,11 @@ public class LdapConnection extends AbstractConnection {
* @return persons map
* @throws IOException on error
*/
public Map<String, ExchangeSession.Contact> findInGAL(ExchangeSession session) throws IOException {
public Map<String, ExchangeSession.Contact> findInGAL(ExchangeSession session, Set<String> returningAttributes, int sizeLimit) throws IOException {
Map<String, ExchangeSession.Contact> persons = null;
for (LdapFilter child : criteria) {
Map<String, ExchangeSession.Contact> childFind = child.findInGAL(session);
Map<String, ExchangeSession.Contact> childFind = child.findInGAL(session, returningAttributes, sizeLimit);
if (childFind != null) {
if (persons == null) {
@ -1091,15 +1077,7 @@ public class LdapConnection extends AbstractConnection {
ExchangeSession.Condition condition = null;
if (operator == LDAP_FILTER_EQUALITY) {
try {
// check imapUid value
if ("imapUid".equals(contactAttributeName)) {
Integer.parseInt(value);
}
condition = session.isEqualTo(contactAttributeName, value);
} catch (NumberFormatException e) {
// ignore condition
}
condition = session.isEqualTo(contactAttributeName, value);
} else if ("*".equals(value)) {
condition = session.not(session.isNull(contactAttributeName));
// do not allow substring search on integer field imapUid
@ -1120,7 +1098,7 @@ public class LdapConnection extends AbstractConnection {
return true;
}
String personAttributeValue = person.get(getGalFindAttributeName());
String personAttributeValue = person.get(attributeName);
if (personAttributeValue == null) {
// No value to allow for filter match
@ -1139,7 +1117,7 @@ public class LdapConnection extends AbstractConnection {
return false;
}
public Map<String, ExchangeSession.Contact> findInGAL(ExchangeSession session) throws IOException {
public Map<String, ExchangeSession.Contact> findInGAL(ExchangeSession session, Set<String> returningAttributes, int sizeLimit) throws IOException {
if (canIgnore) {
return null;
}
@ -1148,7 +1126,7 @@ public class LdapConnection extends AbstractConnection {
if (galFindAttributeName != null) {
// quick fix for cn=* filter
Map<String, ExchangeSession.Contact> galPersons = session.galFind(session.startsWith(attributeName, "*".equals(value) ? "A" : value));
Map<String, ExchangeSession.Contact> galPersons = session.galFind(session.startsWith(attributeName, "*".equals(value) ? "A" : value), returningAttributes, sizeLimit);
if (operator == LDAP_FILTER_EQUALITY) {
// Make sure only exact matches are returned
@ -1278,7 +1256,7 @@ public class LdapConnection extends AbstractConnection {
// then in GAL
if (persons == null || persons.isEmpty()) {
persons = session.galFind(session.isEqualTo("uid", uid));
persons = session.galFind(session.isEqualTo("uid", uid), returningAttributes, sizeLimit);
ExchangeSession.Contact person = persons.get(uid.toLowerCase());
// filter out non exact results
@ -1315,7 +1293,7 @@ public class LdapConnection extends AbstractConnection {
// full search
for (char c = 'A'; c < 'Z'; c++) {
if (!abandon && persons.size() < sizeLimit) {
for (ExchangeSession.Contact person : session.galFind(session.startsWith("uid", String.valueOf(c))).values()) {
for (ExchangeSession.Contact person : session.galFind(session.startsWith("uid", String.valueOf(c)), returningAttributes, sizeLimit).values()) {
persons.put(person.get("uid"), person);
if (persons.size() == sizeLimit) {
break;
@ -1341,7 +1319,7 @@ public class LdapConnection extends AbstractConnection {
}
}
if (!abandon && persons.size() < sizeLimit) {
for (ExchangeSession.Contact person : ldapFilter.findInGAL(session).values()) {
for (ExchangeSession.Contact person : ldapFilter.findInGAL(session, returningAttributes, sizeLimit).values()) {
if (persons.size() == sizeLimit) {
break;
}
@ -1446,19 +1424,6 @@ public class LdapConnection extends AbstractConnection {
boolean needObjectClasses = returningAttributes.contains("objectclass") || returningAttributes.isEmpty();
boolean iCalSearch = returningAttributes.contains("apple-serviceslocator");
boolean returnAllAttributes = returningAttributes.isEmpty();
boolean needDetails = returnAllAttributes;
if (!needDetails) {
for (String attributeName : EXTENDED_ATTRIBUTES) {
if (returningAttributes.contains(attributeName)) {
needDetails = true;
break;
}
}
}
// iCal search, do not lookup details
if (iCalSearch) {
needDetails = false;
}
for (ExchangeSession.Contact person : persons.values()) {
if (abandon) {

View File

@ -48,20 +48,20 @@ public class TestEwsExchangeSession extends AbstractExchangeSessionTestCase {
public void testGalFind() throws IOException {
// find a set of contacts
Map<String, ExchangeSession.Contact> contacts = ewsSession.galFind(ewsSession.startsWith("cn", "a"));
Map<String, ExchangeSession.Contact> contacts = ewsSession.galFind(ewsSession.startsWith("cn", "a"), null, 100);
for (ExchangeSession.Contact contact : contacts.values()) {
System.out.println(contact);
}
if (!contacts.isEmpty()) {
ExchangeSession.Contact testContact = contacts.values().iterator().next();
contacts = ewsSession.galFind(ewsSession.isEqualTo("cn", testContact.get("cn")));
contacts = ewsSession.galFind(ewsSession.isEqualTo("cn", testContact.get("cn")), null, 100);
assertEquals(1, contacts.size());
contacts = ewsSession.galFind(ewsSession.isEqualTo("email1", testContact.get("email1")));
contacts = ewsSession.galFind(ewsSession.isEqualTo("email1", testContact.get("email1")), null, 100);
assertEquals(1, contacts.size());
contacts = ewsSession.galFind(ewsSession.startsWith("email1", testContact.get("email1")));
contacts = ewsSession.galFind(ewsSession.startsWith("email1", testContact.get("email1")), null, 100);
assertEquals(1, contacts.size());
contacts = ewsSession.galFind(ewsSession.and(ewsSession.isEqualTo("cn", testContact.get("cn")),
ewsSession.startsWith("email1", testContact.get("email1"))));
ewsSession.startsWith("email1", testContact.get("email1"))), null, 100);
assertEquals(1, contacts.size());
}
}

View File

@ -18,13 +18,15 @@
*/
package davmail.ldap;
import davmail.AbstractDavMailTestCase;
import davmail.DavGateway;
import davmail.Settings;
import davmail.exchange.AbstractExchangeSessionTestCase;
import davmail.exchange.ExchangeSessionFactory;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;
@ -34,7 +36,7 @@ import java.util.Hashtable;
/**
* Test LDAP.
*/
public class TestLdap extends AbstractDavMailTestCase {
public class TestLdap extends AbstractExchangeSessionTestCase {
InitialLdapContext ldapContext;
@Override
@ -83,4 +85,17 @@ public class TestLdap extends AbstractDavMailTestCase {
searchControls.setReturningAttributes(new String[]{"custom1", "mozillausehtmlmail", "postalcode", "custom2", "custom3", "custom4", "street", "surname", "telephonenumber", "mozillahomelocalityname", "orgunit", "mozillaworkstreet2", "xmozillanickname", "mozillahomestreet", "description", "cellphone", "homeurl", "mozillahomepostalcode", "departmentnumber", "postofficebox", "st", "objectclass", "sn", "ou", "fax", "mozillahomeurl", "mozillahomecountryname", "streetaddress", "cn", "company", "mozillaworkurl", "mobile", "region", "birthmonth", "birthday", "labeleduri", "carphone", "department", "xmozillausehtmlmail", "givenname", "nsaimid", "workurl", "facsimiletelephonenumber", "mozillanickname", "title", "nscpaimscreenname", "xmozillasecondemail", "mozillacustom3", "countryname", "mozillacustom4", "mozillacustom1", "mozillacustom2", "homephone", "mozillasecondemail", "pager", "zip", "mail", "c", "mozillahomestate", "o", "l", "birthyear", "modifytimestamp", "locality", "commonname", "notes", "pagerphone", "mozillahomestreet2"});
NamingEnumeration<SearchResult> searchResults = ldapContext.search("ou=people", "(objectclass=*)", searchControls);
}
public void testGalfind() throws NamingException {
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
// searchControls.setReturningAttributes(new String[]{"uid"});
NamingEnumeration<SearchResult> searchResults = ldapContext.search("ou=people", "(uid="+session.getAlias()+ ')', searchControls);
assertTrue(searchResults.hasMore());
SearchResult searchResult = searchResults.next();
Attributes attributes = searchResult.getAttributes();
Attribute attribute = attributes.get("uid");
assertEquals(session.getAlias(), attribute.get());
assertNotNull(attributes.get("givenName"));
}
}