- private Prevayler prevayler;
- private Cache cache;
-
- public static class Cache implements Serializable {
- public final int uidValidity = Math.abs(new Random().nextInt());
- private final Hashtable<String,Entry> byname = new Hashtable<String,Entry>();
- private final Hashtable<Integer,Entry> byuid = new Hashtable<Integer,Entry>();
- private final ArrayList<Entry> linear = new ArrayList<Entry>();
- public final File dir;
- private int uidNext = 0;
-
- public Cache(File dir) { this.dir = dir; }
-
- public void init(final Prevayler prevayler) throws IOException {
- dir.mkdirs();
- long time = System.currentTimeMillis();
- Log.info(this, "initializing maildir " + dir.getParent());
-
- // Drop entries whose files have vanished
- ArrayList<Transaction> kill = new ArrayList<Transaction>();
- for(String s : byname.keySet())
- if (!new File(dir.getParent() + slash + s).exists())
- kill.add(byname.get(s).delete(null));
- for(Transaction t : kill) prevayler.execute(t);
-
- // Make entries for new files which have appeared
- for(String file : new File(dir.getParent()).list()) {
- File f = new File(dir.getParent() + slash + file);
- if (file.charAt(0)!='.' && !f.isDirectory()) {
- Entry e = get(file);
- if (e == null)
- prevayler.execute(Entry.create(f));
- else if ((f.lastModified() == MAGIC_DATE) != e.seen())
- prevayler.execute(e.seen(f, !e.seen()));
- }
- }
-
- // Take a snapshot for posterity
- if (System.currentTimeMillis() - time > 1000 * 5)
- Log.info(this, " done initializing maildir " + dir.getParent());
- new Thread() { public void run() {
- try { prevayler.takeSnapshot(); } catch (Exception e) { Log.error(this, e); } } }.start();
- }
-
-
- public synchronized int size() { return linear.size(); }
- public synchronized int uidNext() { return uidNext; }
- public synchronized Entry get(int uid) { return byuid.get(uid); }
- public synchronized Entry getLinear(int num) { return linear.get(num); }
- public synchronized Entry get(String name) { return byname.get(name); }
-
- public static class Entry implements Serializable {
- private final byte[] header;
- public final String name;
- public final int uid;
- private boolean seen;
- private Entry(String name, boolean seen, int uid, byte[] header) {
- this.name = name; this.seen = seen; this.uid = uid; this.header = header; }
-
- // Accessors //////////////////////////////////////////////////////////////////////////////
-
- public boolean seen() { return seen; }
- public Headers headers() { return new Headers(new Stream(new ByteArrayInputStream(header)), true); }
- public Message message(Cache cache) { try {
- FileInputStream fis = null;
- try {
- return Message.newMessage(new Fountain.File(new File(cache.dir.getParent() + slash + name)));
- } finally { if (fis != null) fis.close(); }
- } catch (IOException e) { throw new MailException.IOException(e);
- } catch (Message.Malformed e) { throw new MailException(e.getMessage()); }
- }
-
- // Transactions //////////////////////////////////////////////////////////////////////////////
-
- public static Transaction create(File f) throws IOException {
- final boolean seen = f.lastModified() == MAGIC_DATE;
- final String name = f.getName();
- final byte[] header = new Headers(new Stream(new FileInputStream(f)), true).getString().getBytes();
- return new Transaction() {
- public void executeOn(Object o, Date now) {
- Cache cache = (Cache)o;
- synchronized(cache) {
- Entry e = new Entry(name, seen, cache.uidNext++, header);
- cache.linear.add(e);
- cache.byuid.put(e.uid, e);
- cache.byname.put(e.name, e);
- } } };
- }
-
- public Transaction seen(File f, final boolean seen) {
- f.setLastModified(seen ? MAGIC_DATE : System.currentTimeMillis());
- final int uid = this.uid;
- return new Transaction() {
- public void executeOn(Object o, Date now) {
- Cache cache = (Cache)o;
- synchronized(cache) {
- cache.get(uid).seen = seen;
- } } };
- }
- public Transaction delete(File f) {
- if (f != null && f.exists()) f.delete();
- final int uid = this.uid;
- return new Transaction() {
- public void executeOn(Object o, Date now) {
- Cache cache = (Cache)o;
- synchronized(cache) {
- Cache.Entry e = cache.get(uid);
- cache.byname.remove(e.name);
- cache.linear.remove(e);
- cache.byuid.remove(uid);
- } } };
- }
- }
- }