0

I'm using GNU NNTP to connect to leafnode, which is an NNTP server, on localhost. The GNU API utilizes javax.mail.Message, which comes with the following caveat:

From the Message API:

..the message number for a particular Message can change during a session if other messages in the Folder are deleted and expunged.

So, currently, I'm using javax.mail.search to search for a known message. Unfortunately, for each search the entire folder has be searched. I could keep the folder open and in that way speed the search a bit, but it just seems klunky.

What's an alternate approach to using javax.mail.search? This:

    SearchTerm st = new MessageIDTerm(id);
    List<Message> messages = Arrays.asList(folder.search(st));

works fine when the javax.mail.Folder only has a few Message's. However, for very large Folder's there must be a better approach. Instead of the Message-ID header field, Xref might be preferable, but still has the same fundamental problem of searching strings.

Here's the database, which just needs to hold enough information to find/get/search the Folder's for a specified message:

mysql> 
mysql> use usenet;show tables;
Database changed
+------------------+
| Tables_in_usenet |
+------------------+
| articles         |
| newsgroups       |
+------------------+
2 rows in set (0.00 sec)

mysql> 
mysql> describe articles;
+--------------+--------------+------+-----+---------+----------------+
| Field        | Type         | Null | Key | Default | Extra          |
+--------------+--------------+------+-----+---------+----------------+
| ID           | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| MESSAGEID    | varchar(255) | YES  |     | NULL    |                |
| NEWSGROUP_ID | bigint(20)   | YES  | MUL | NULL    |                |
+--------------+--------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

mysql> 
mysql> describe newsgroups;
+-----------+--------------+------+-----+---------+----------------+
| Field     | Type         | Null | Key | Default | Extra          |
+-----------+--------------+------+-----+---------+----------------+
| ID        | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| NEWSGROUP | varchar(255) | YES  |     | NULL    |                |
+-----------+--------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

mysql> 

While the schema is very simple at the moment, I plan to add complexity to it.

messages are queried for with getMessage():

package net.bounceme.dur.usenet.model;

import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.mail.*;
import javax.mail.search.MessageIDTerm;
import javax.mail.search.SearchTerm;
import net.bounceme.dur.usenet.controller.Page;

public enum Usenet {

    INSTANCE;
    private final Logger LOG = Logger.getLogger(Usenet.class.getName());
    private Properties props = new Properties();
    private Folder root = null;
    private Store store = null;
    private List<Folder> folders = new ArrayList<>();
    private Folder folder = null;

    Usenet() {
        LOG.fine("controller..");
        props = PropertiesReader.getProps();
        try {
            connect();
        } catch (Exception ex) {
            Logger.getLogger(Usenet.class.getName()).log(Level.SEVERE, "FAILED TO LOAD MESSAGES", ex);
        }
    }

    public void connect() throws Exception {
        LOG.fine("Usenet.connect..");
        Session session = Session.getDefaultInstance(props);
        session.setDebug(true);
        store = session.getStore(new URLName(props.getProperty("nntp.host")));
        store.connect();
        root = store.getDefaultFolder();
        setFolders(Arrays.asList(root.listSubscribed()));
    }

    public List<Message> getMessages(Page page) throws Exception {
        Newsgroup newsgroup = new Newsgroup(page);
        LOG.fine("fetching.." + newsgroup);
        folder = root.getFolder(newsgroup.getNewsgroup());
        folder.open(Folder.READ_ONLY);
        List<Message> messages = Arrays.asList(folder.getMessages());
        LOG.fine("..fetched " + folder);
        return Collections.unmodifiableList(messages);
    }

    public List<Folder> getFolders() {
        LOG.fine("folders " + folders);
        return Collections.unmodifiableList(folders);
    }

    private void setFolders(List<Folder> folders) {
        this.folders = folders;
    }

    public Message getMessage(Newsgroup newsgroup, Article article) throws MessagingException {
        LOG.fine("\n\ntrying.." + newsgroup + article);
        String id = article.getMessageId();
        Message message = null;
        folder = root.getFolder(newsgroup.getNewsgroup());
        folder.open(Folder.READ_ONLY);
        SearchTerm st = new MessageIDTerm(id);
        List<Message> messages = Arrays.asList(folder.search(st));
        LOG.severe(messages.toString());
        if (!messages.isEmpty()) {
            message = messages.get(0);
        }
        LOG.info(message.getSubject());
        return message;
    }
}

The problem, which I'm only now realizing, is that:

...the message number for a particular Message can change during a session if other messages in the Folder are deleted and expunged.

Regardless of which particular header is used, it's something like:

Message-ID: <x1-CZwog1NTZLd68+JJY35Zrl9OqXE@gwene.org>

or

Xref: dur.bounceme.net gwene.com.economist:541

So that there's always a String which needs parsing and searching, which is quite awkward.

I do notice that MimeMessage has a very convenient getMessageID method. Unfortunately, GNU uses javax.mail.Message and not MimeMessage. Granted, it's possible to instantiate a folder and MimeMessage, but I don't see any savings there in that from one run to another there's no guarantee that getMessageID will return the correct message.

The awkward solution I see is to maybe create a persistent folder of MimeMessage's, but that seems like overkill.

Hence, using a header, either Xref or Message-ID and then parsing and searching strings...

Is there a better way?

Mohayemin
  • 3,841
  • 4
  • 25
  • 54
Thufir
  • 8,216
  • 28
  • 125
  • 273

1 Answers1

2

javax.mail is a lowest-common-denominator API, and it's behavior depends entirely on what is the backend. So, without knowing what you are talking to, it's not really possible to give a good answer to your question. Chances are, however, that you'll need to talk directly to whatever you're talking to and learn more about its behavior.

This might be a comment rather than an answer, but I'm thinking that the information that this API is just a thin layer might be enough information to justify.

bmargulies
  • 97,814
  • 39
  • 186
  • 310
  • I'm using the GNU NNTP library to talk to a leafnode NNTP server running on localhost. Pardon, forgot to include that, I was trying to be succinct. I'll update my question. – Thufir Aug 12 '12 at 22:49