Skip to content

Commit

Permalink
added caching of message envelopes. issue #2724
Browse files Browse the repository at this point in the history
  • Loading branch information
j-dimension committed Dec 8, 2024
1 parent df84e10 commit d467adf
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1725,7 +1725,7 @@ public boolean isCellEditable(int row, int column) {
this.tblMails.setDefaultRenderer(Object.class, new EmailTableCellRenderer());

ProgressIndicator dlg = new ProgressIndicator(EditorsRegistry.getInstance().getMainWindow(), true);
LoadFolderAction a = new LoadFolderAction(dlg, folder, tblMails, sortCol, scrollToRow, searchTerm);
LoadFolderAction a = new LoadFolderAction(dlg, folderC, tblMails, sortCol, scrollToRow, searchTerm);
a.start();

} catch (Exception ex) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -664,12 +664,17 @@
package com.jdimension.jlawyer.client.mail;

import com.jdimension.jlawyer.email.CommonMailUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.StoreClosedException;
import javax.mail.UIDFolder;
import org.apache.log4j.Logger;

/**
Expand All @@ -689,10 +694,8 @@ public class FolderContainer {

double retentionTime = -1;

// private Message[] cachedMessages=null;
// private String cachedMessagesKey=null;


private Map<Long, Message> cachedMessages = new HashMap<>();

static {
folderNameMapping.put(CommonMailUtils.INBOX, "Posteingang");
folderNameMapping.put(CommonMailUtils.SENT, "Gesendet");
Expand All @@ -709,6 +712,7 @@ public FolderContainer(Folder f) {
public void resetCaches() {
this.cachedToStringUpdated = -1;
this.cachedUnreadUpdated = -1;
this.cachedMessages.clear();
}

private double getRetentionTime() {
Expand Down Expand Up @@ -757,7 +761,7 @@ public String toString() {

if (this.cachedToStringUpdated == -1 || ((System.currentTimeMillis() - cachedToStringUpdated) > this.getRetentionTime())) {
try {

String name = this.folder.getName();

Set mapKey = folderNameMapping.keySet();
Expand Down Expand Up @@ -802,4 +806,67 @@ public void setFolder(Folder folder) {
this.folder = folder;
}

Message[] getUncachedMessages(Message[] messages) {
if (!(this.folder instanceof UIDFolder)) {
// no caching - return all messages to be fetched from server
return messages;
} else {
Set<Long> serverUids = new HashSet<>();
UIDFolder uidFolder = (UIDFolder) this.folder;
for (Message message : messages) {
try {
long uid = uidFolder.getUID(message);
serverUids.add(uid);
} catch (Exception ex) {
log.error("unable to get UID of message", ex);
}
}

// Remove messages from the cache that are no longer on the server
cachedMessages.keySet().removeIf(uid -> !serverUids.contains(uid));

// Determine which UIDs are new
Set<Long> newUids = new HashSet<>(serverUids);
newUids.removeAll(cachedMessages.keySet());

ArrayList<Message> uncached=new ArrayList<>();
for (Message message : messages) {
try {
long uid = uidFolder.getUID(message);
if(newUids.contains(uid)) {
uncached.add(message);
}
} catch (Exception ex) {
log.error("unable to get UID of message", ex);
}
}
return uncached.toArray(new Message[0]);


}
}

public void addCachedMessages(Message[] messages) {
if (this.folder instanceof UIDFolder) {
UIDFolder uidFolder = (UIDFolder) this.folder;
for (Message message : messages) {
try {
long uid = uidFolder.getUID(message);
this.cachedMessages.put(uid, message);
} catch (Exception ex) {
log.error("unable to get UID of message", ex);
}
}
}
}

public Message[] getCachedMessages(Message[] messages) {
if(this.cachedMessages.isEmpty()) {
return messages;
} else {
return this.cachedMessages.values().toArray(new Message[0]);
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -671,12 +671,14 @@
import java.awt.Rectangle;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import javax.mail.Address;
import javax.mail.FetchProfile;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.UIDFolder;
import javax.mail.search.AndTerm;
import javax.mail.search.BodyTerm;
import javax.mail.search.FlagTerm;
Expand All @@ -699,13 +701,15 @@ public class LoadFolderAction extends ProgressableAction {
private static final Logger log = Logger.getLogger(LoadFolderAction.class.getName());
private final SimpleDateFormat df = new SimpleDateFormat("dd.MM.yyyy, HH:mm");

private Folder f = null;
private FolderContainer f = null;
private JTable table = null;
private int sortCol = -1;
private int scrollToRow = -1;
private String searchTerm = null;

private int messageCount=-1;

public LoadFolderAction(ProgressIndicator i, Folder f, JTable table, int sortCol, int scrollToRow, String searchTerm) {
public LoadFolderAction(ProgressIndicator i, FolderContainer f, JTable table, int sortCol, int scrollToRow, String searchTerm) {
super(i, false);
this.f = f;
this.table = table;
Expand All @@ -714,14 +718,21 @@ public LoadFolderAction(ProgressIndicator i, Folder f, JTable table, int sortCol
this.searchTerm = searchTerm;
}

private int getMessageCount() {
if(messageCount < 0) {
try {
return f.getFolder().getMessageCount();
} catch (Throwable t) {
log.error(t);
messageCount = 1;
}
}
return messageCount;
}

@Override
public int getMax() {
try {
return f.getMessageCount();
} catch (Throwable t) {
log.error(t);
return 1;
}
return this.getMessageCount();
}

@Override
Expand All @@ -732,8 +743,10 @@ public int getMin() {
@Override
public boolean execute() throws Exception {
try {
if (!(f.isOpen())) {
f.open(Folder.READ_WRITE);
//long start=System.currentTimeMillis();

if (!(f.getFolder().isOpen())) {
f.getFolder().open(Folder.READ_WRITE);
}
// try {
// if (EmailUtils.isIMAP(f)) {
Expand All @@ -742,7 +755,7 @@ public boolean execute() throws Exception {
// } catch (Throwable t) {
// log.error("Could not expunge folder", t);
// }
// System.out.println("load 20 = " + (System.currentTimeMillis() - start));
//System.out.println("load 20 = " + (System.currentTimeMillis() - start));

ClientSettings cs = ClientSettings.getInstance();
String restriction = cs.getConfiguration(ClientSettings.CONF_MAIL_DOWNLOADRESTRICTION, "" + LoadFolderRestriction.RESTRICTION_50);
Expand All @@ -755,7 +768,7 @@ public boolean execute() throws Exception {
}

int fromIndex = 1;
int toIndex = f.getMessageCount();
int toIndex = this.getMessageCount();
int maxQuantity = Integer.MAX_VALUE;
switch (currentRestriction.getRestriction()) {
case LoadFolderRestriction.RESTRICTION_20:
Expand All @@ -778,19 +791,20 @@ public boolean execute() throws Exception {
break;
}

//System.out.println("load 30 = " + (System.currentTimeMillis() - start));
Message[] messages = null;
FlagTerm notDeleted = new FlagTerm(new Flags(Flags.Flag.DELETED), false);
if (StringUtils.isEmpty(this.searchTerm)) {
if (currentRestriction.getRestriction() == LoadFolderRestriction.RESTRICTION_UNREAD) {
// Combine unread filter with notDeleted filter
FlagTerm unread = new FlagTerm(new Flags(Flags.Flag.SEEN), false);
AndTerm filter = new AndTerm(unread, notDeleted);
messages = f.search(filter, messages);
messages = f.getFolder().search(filter, messages);
} else {
messages = f.getMessages(fromIndex, toIndex);
messages = f.getFolder().getMessages(fromIndex, toIndex);

// Apply the filter to the subset of messages
messages = f.search(notDeleted, messages);
messages = f.getFolder().search(notDeleted, messages);
}
} else {
maxQuantity = Integer.MAX_VALUE;
Expand All @@ -806,14 +820,38 @@ public boolean execute() throws Exception {

// Combine the OR term with notDeleted filter
AndTerm filter = new AndTerm(orTerm, notDeleted);
messages = f.search(filter);
messages = f.getFolder().search(filter);
}

messages = Arrays.stream(messages)
.limit(maxQuantity+1)
.toArray(Message[]::new);

//System.out.println("load 40 = " + (System.currentTimeMillis() - start));

if (f.getFolder() instanceof UIDFolder) {
// get all the UIDs
FetchProfile fpUid = new FetchProfile();
fpUid.add(UIDFolder.FetchProfileItem.UID);
f.getFolder().fetch(messages, fpUid);
}

//System.out.println("load 50 = " + (System.currentTimeMillis() - start));
Message[] uncachedMessages = f.getUncachedMessages(messages);

//System.out.println("load 60 = " + (System.currentTimeMillis() - start));
FetchProfile fp = new FetchProfile();
fp.add(FetchProfile.Item.ENVELOPE);
fp.add(FetchProfile.Item.FLAGS);
f.fetch(messages, fp);

f.getFolder().fetch(uncachedMessages, fp);


//System.out.println("load 70 = " + (System.currentTimeMillis() - start));
f.addCachedMessages(uncachedMessages);

messages=f.getCachedMessages(messages);

//System.out.println("load 80 = " + (System.currentTimeMillis() - start));
HashMap<String, String> decodedMap = new HashMap<>();
final int indexMax = messages.length - 1;
ArrayList<Object[]> tableRows = new ArrayList<>();
Expand Down Expand Up @@ -845,8 +883,8 @@ public boolean execute() throws Exception {
continue;
}

if (!(f.isOpen())) {
f.open(Folder.READ_WRITE);
if (!(f.getFolder().isOpen())) {
f.getFolder().open(Folder.READ_WRITE);
}

String fromCheck = "unbekannt";
Expand Down Expand Up @@ -919,22 +957,25 @@ public boolean execute() throws Exception {
}
}

try {
table.getRowSorter().toggleSortOrder(this.sortCol);

} catch (Throwable t) {
log.error("Error sorting mails", t);
}
//System.out.println("load 90 = " + (System.currentTimeMillis() - start));


SwingUtilities.invokeLater(() -> {
try {
table.getRowSorter().toggleSortOrder(this.sortCol);

} catch (Throwable t) {
log.error("Error sorting mails", t);
}
ComponentUtils.autoSizeColumns(table, 0);
});

//System.out.println("load 100 = " + (System.currentTimeMillis() - start));
new Thread(() -> {
try {
Thread.sleep(5000);
if (f.isOpen()) {
EmailUtils.closeIfIMAP(f);
if (f.getFolder().isOpen()) {
EmailUtils.closeIfIMAP(f.getFolder());
}
} catch (Throwable t) {
log.error(t);
Expand Down

0 comments on commit d467adf

Please sign in to comment.