package fr.keemto.provider.exchange.importer;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
import fr.keemto.core.fetching.FetchingException;
import microsoft.exchange.webservices.data.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
public class EmailExchangeService implements Enumeration<List<EmailMessage>> {
private static final Logger log = LoggerFactory.getLogger(EmailExchangeService.class);
private static final int PAGE_OFFSET = 100;
private static final long MINIMAL_MILLIS_BETWEEN_TO_MAIL = 1000L;
private final ExchangeService exchangeService;
private final ItemView offsetView;
private final SearchFilter.IsGreaterThan filter;
private PartialEmailList currentPartialEmailList;
public EmailExchangeService(long emailNewerThan, ExchangeService exchangeService) {
Date greaterThan = new Date(emailNewerThan + MINIMAL_MILLIS_BETWEEN_TO_MAIL);
filter = new SearchFilter.IsGreaterThan(EmailMessageSchema.DateTimeCreated, greaterThan);
offsetView = new ItemView(PAGE_OFFSET);
this.exchangeService = exchangeService;
}
@Override
public boolean hasMoreElements() {
if (currentPartialEmailList == null) return true;
return currentPartialEmailList.hasMoreItems;
}
@Override
public List<EmailMessage> nextElement() {
log.debug("Retrieving email ids with offset {}", offsetView.getOffset());
try {
FindItemsResults<Item> itemsResults = exchangeService.findItems(WellKnownFolderName.Inbox, filter, offsetView);
int leftItems = itemsResults.getTotalCount() - offsetView.getOffset();
log.debug("{} items ids has been retrieved, {} items left on remote server.", itemsResults.getItems().size(), leftItems);
List<ItemId> ids = extractItemIdsFrom(itemsResults);
currentPartialEmailList = new PartialEmailList(ids, itemsResults.isMoreAvailable(), exchangeService);
incrementOffset();
return currentPartialEmailList.getFullBindedMessages();
} catch (Exception e) {
throw new ExchangeServiceException("An error has occurred when trying to retrieve messages from exchange WS service " + exchangeService.getUrl(), e);
}
}
private void incrementOffset() {
offsetView.setOffset(offsetView.getOffset() + PAGE_OFFSET);
}
private List<ItemId> extractItemIdsFrom(FindItemsResults<Item> itemsResults) {
return Lists.transform(itemsResults.getItems(), new Function<Item, ItemId>() {
@Override
public ItemId apply(Item item) {
try {
return item.getId();
} catch (ServiceLocalException e) {
throw new FetchingException(e);
}
}
});
}
private static class PartialEmailList {
private final boolean hasMoreItems;
private final List<ItemId> ids;
private final ExchangeService exchangeService;
private PartialEmailList(List<ItemId> ids, boolean hasMoreItems, ExchangeService exchangeService) {
this.ids = ids;
this.hasMoreItems = hasMoreItems;
this.exchangeService = exchangeService;
}
public List<EmailMessage> getFullBindedMessages() throws Exception {
if (ids.isEmpty()) return new ArrayList<EmailMessage>();//bindToItems does not handle empty ids list
ServiceResponseCollection<GetItemResponse> response = exchangeService.bindToItems(ids, getPropertiesToLoadForEmailMessage());
log.debug("email message data has been bounded remotely for {} items", ids.size());
return convertResponseToEmailList(response);
}
private PropertySet getPropertiesToLoadForEmailMessage() throws Exception {
PropertySet ps = new PropertySet();
ps.add(EmailMessageSchema.Id);
ps.add(EmailMessageSchema.DateTimeCreated);
ps.add(EmailMessageSchema.Sender);
ps.add(EmailMessageSchema.ToRecipients);
ps.add(EmailMessageSchema.Subject);
ps.add(EmailMessageSchema.Body);
ps.add(EmailMessageSchema.UniqueBody);
return ps;
}
private List<EmailMessage> convertResponseToEmailList(ServiceResponseCollection<GetItemResponse> bindedItems) {
List<EmailMessage> messages = new ArrayList<EmailMessage>();
for (GetItemResponse bindedItem : bindedItems) {
EmailMessage message = (EmailMessage) bindedItem.getItem();
messages.add(message);
}
return messages;
}
}
}