001 package edu.harvard.deas.hyperenc.gui; 002 003 import java.util.Collection; 004 import java.util.Collections; 005 import java.util.HashMap; 006 import java.util.HashSet; 007 import java.util.Map; 008 import java.util.Set; 009 010 import edu.harvard.deas.hyperenc.Contact; 011 012 013 /** 014 * Stores collections of GuiMessages. Supports retrieval of all GuiMessages from 015 * a particular sender. This implementation is backed by the Java Collections 016 * API. It is not backed by any persistent medium, and so the contained messages 017 * will be lost when the VM terminates unless the application explicitly writes 018 * the contained messages to disk. 019 * <p> 020 * All storage in this MessageStorage is done by reference; the returned 021 * GuiMessage is the same object reference as the one that was stored. 022 * <p> 023 * <b>Thread safety:</b> This implementation is unconditionally thread-safe. 024 */ 025 public class BasicMessageStorage extends MessageStorage { 026 // The map returned from synchronizedMap is conditionally thread-safe; so long 027 // as we synchronize on it when iterating, concurrent access is safe. Because 028 // the map or its iterators are not exposed outside this class, the class is 029 // unconditionally thread-safe. 030 private Map<Contact,Set<GuiMessage>> messagesBySender = 031 Collections.synchronizedMap(new HashMap<Contact,Set<GuiMessage>>()); 032 033 /** 034 * Constructs a new, empty BasicMessageStorage. 035 */ 036 public BasicMessageStorage() { 037 } 038 039 @Override 040 public void addMessage(GuiMessage msg) { 041 Set<GuiMessage> messages; 042 if (messagesBySender.containsKey(msg.getSender())) { 043 messages = messagesBySender.get(msg.getSender()); 044 assert(messages != null); 045 } else { 046 // initialize it if necessary 047 messages = new HashSet<GuiMessage>(); 048 messagesBySender.put(msg.getSender(), messages); 049 } 050 051 messages.add(msg); 052 } 053 054 @Override 055 public GuiMessage getMessage(int id) { 056 synchronized (messagesBySender) { 057 for (Set<GuiMessage> gmset : messagesBySender.values()) { 058 for (GuiMessage gm : gmset) { 059 if (gm.getID() == id) { 060 return gm; 061 } 062 } 063 } 064 return null; 065 } 066 } 067 068 @Override 069 public Collection<GuiMessage> getMessagesBySender(Contact contact) { 070 if (messagesBySender.containsKey(contact)) { 071 Set<GuiMessage> msgsFromSender = messagesBySender.get(contact); 072 assert(msgsFromSender != null); 073 return new HashSet<GuiMessage>(msgsFromSender); 074 } else { 075 return new HashSet<GuiMessage>(); 076 } 077 } 078 079 @Override 080 public GuiMessage removeMessage(int id) { 081 synchronized (messagesBySender) { 082 for (Set<GuiMessage> gmset : messagesBySender.values()) { 083 for (GuiMessage gm : gmset) { 084 if (gm.getID() == id) { 085 gmset.remove(gm); 086 return gm; 087 } 088 } 089 } 090 return null; 091 } 092 } 093 094 }