001 package edu.harvard.deas.hyperenc; 002 003 import java.io.File; 004 import java.io.Serializable; 005 import java.util.ArrayList; 006 import java.util.Iterator; 007 import java.util.List; 008 import java.util.NoSuchElementException; 009 010 import javax.mail.Address; 011 012 /** 013 * A contact list backed by a database on disk. This class uses PersistentMap to 014 * store the Contacts to disk. Because PersistentMap provides an unsorted view 015 * of the data, this class also stores all Contacts in the list in a sorted 016 * collection in memory; all changes to this list are made in the in-memory copy 017 * and also written through to disk via the PersistentMap. 018 * <p> 019 * <code>DBContactList</code> attempts to read in any existing contact list from 020 * disk that has the same owner. If none is found, a new, empty DBContactList is 021 * created. Because entries are stored in the on-disk database in an inherently 022 * unsorted manner, the order of Contacts in a DBContactList may not be 023 * consistent across multiple sessions—the order is subject to change 024 * every time the data is read in from disk. 025 * 026 * @see PersistentMap 027 */ 028 public class DBContactList extends ContactList { 029 // ignore values and use a PersistentMap as a set -- kind of lame, but it works 030 private PersistentMap<Contact,Obj> myMap; 031 032 // should always contain the same values as myMap.keySet() 033 private List<Contact> myList; 034 035 // owner of this ContactList -- should be included in getContact calls, but not 036 // in get calls 037 private Contact myOwner; 038 039 // placeholder class for values of the map 040 private static class Obj implements Serializable { 041 private static final long serialVersionUID = 1L; 042 } 043 044 /** 045 * Creates a new DBContactList. Attempts to read in any existing contact list 046 * from disk that has the same owner. If none is found, a new, empty 047 * DBContactList is created. Because entries are stored in the on-disk 048 * database in an inherently unsorted manner, the order of Contacts in a 049 * DBContactList may not be consistent across multiple sessions—the 050 * order of the Contacts in the created list may be different from the order 051 * in which they were written by a previous instance of DBContactList. 052 * 053 * @param owner 054 * the owner of this list (usually the Contact corresponding to the 055 * user of the hyper-encryption application) 056 * @param envPath 057 * The path on disk of the database backing this map. 058 * Must be readable and writable. If it doesn't 059 * exist, it will be created. If <code>null</code>, the default 060 * environment specified by {@link PersistentMap#DEFAULT_HOME} is used. 061 * @see PersistentMap 062 */ 063 public DBContactList(Contact owner, File envPath) { 064 myMap = PersistentMap.getInstance(owner.getEmail().toString() + ".Contacts", 065 Contact.class, 066 Obj.class, 067 envPath); 068 myList = new ArrayList<Contact>(myMap.keySet()); 069 myOwner = owner; 070 } 071 072 /** 073 * Equivalent to <code>DBContactList(owner, null)</code>. 074 * 075 * @param owner 076 * the owner of this list (usually the Contact corresponding to the 077 * user of the hyper-encryption application) 078 */ 079 public DBContactList(Contact owner) { 080 this(owner, null); 081 } 082 083 @Override 084 public Iterator<Contact> iterator() { 085 return myList.iterator(); 086 } 087 088 @Override 089 public void addContact(Contact c) { 090 myMap.put(c, new Obj()); 091 myList.add(c); 092 } 093 094 @Override 095 public void removeContact(Contact c) { 096 myMap.remove(c); 097 myList.remove(c); 098 } 099 100 @Override 101 public Contact get(int index) { 102 return myList.get(index); 103 } 104 105 @Override 106 public int size() { 107 return myList.size(); 108 } 109 110 @Override 111 public boolean isEmpty() { 112 return myList.isEmpty(); 113 } 114 115 /** 116 * Returns the Contact in this list with e-mail address <code>a</code>. 117 * @param a e-mail address 118 * @return the Contact with the given e-mail address 119 */ 120 @Override 121 public Contact getContact(Address a) { 122 if (a.equals(myOwner.getEmail())) 123 return myOwner; 124 for (Contact c : myList) 125 if (a.equals(c.getEmail())) 126 return c; 127 throw new NoSuchElementException( 128 "Contact list does not contain a Contact with Address " + a); 129 } 130 }