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    }