@Override public Iterable<LocatedReplyThread> locateReplyThreads() { // NOTE(anorth): We must recalculate the anchor locations on each // call as the document does not provide stable elements. However, we // calculate the list of anchor locations on demand. Map<String, Integer> replyLocations = null; List<LocatedReplyThread> inlineReplyThreads = CollectionUtils.newArrayList(); for (WaveletBasedConversationThread reply : getReplyThreads()) { if (replyLocations == null) { replyLocations = findAnchors(); } Integer location = replyLocations.get(reply.getId()); inlineReplyThreads.add(new LocatedReplyThread(reply, (location != null) ? location : Blips.INVALID_INLINE_LOCATION)); } Collections.sort(inlineReplyThreads); return Collections.unmodifiableList(inlineReplyThreads); }
private void observe(WaveletBasedConversationBlip blip) { blips.put(blip.getId(), blip); blip.addListener(new BlipListenerAggregator(blip)); for (WaveletBasedConversationThread thread : blip.getReplyThreads()) { observe(thread); } }
/** * Deletes all threads from this blip. * * @see WaveletBasedConversationBlip#deleteThread(WaveletBasedConversationThread) */ void deleteThreads() { // deleteThread() equivalent is inline here so we can do only one // document traversal to remove inline reply anchors. List<WaveletBasedConversationThread> threads = CollectionUtils.newArrayList(getReplyThreads()); for (WaveletBasedConversationThread threadToDelete : threads) { threadToDelete.deleteBlips(); manifestBlip.removeReply(threadToDelete.getManifestThread()); } clearAllInlineReplyAnchors(); }
/** * Tests that empty threads are not ignored. */ public void testCreateWithEmptyManifestThreadNotIgnored() { ConversationBlip blip = target.getRootThread().appendBlip(); ConversationThread thread = blip.addReplyThread(); WaveletBasedConversation another = mirrorConversation(target); assertNotNull(another.getRootThread().getFirstBlip()); assertTrue(another.getRootThread().getFirstBlip().getReplyThreads().iterator().hasNext()); }
/** * Tests that empty threads are not ignored. */ public void testCreateWithEmptyManifestThreadNotIgnored() { ConversationBlip blip = target.getRootThread().appendBlip(); ConversationThread thread = blip.addReplyThread(); WaveletBasedConversation another = mirrorConversation(target); assertNotNull(another.getRootThread().getFirstBlip()); assertTrue(another.getRootThread().getFirstBlip().getReplyThreads().iterator().hasNext()); }
public void testConcrrentDeletionOfFinalBlipsLeavesEmptyThread() { WaveletBasedConversationBlip first = target.getRootThread().appendBlip(); WaveletBasedConversationThread replyThread = first.addReplyThread(); WaveletBasedConversationBlip b1 = replyThread.appendBlip(); WaveletBasedConversationBlip b2 = replyThread.appendBlip(); // Locally delete b1, remotely delete b2. b1.delete(); replyThread.addListener(threadListener); b2.addListener(blipListener); target.addListener(convListener); remoteRemoveBlip(b2); // Expect blip deletion events and it to be invalid. verify(blipListener).onDeleted(); verify(convListener).onBlipDeleted(b2); assertBlipInvalid(b2); assertThreadValid(replyThread); assertEquals(Arrays.asList(replyThread), CollectionUtils.newArrayList(first.getReplyThreads())); // The manifest now has a thread with no blips. assertEquals(1, first.getManifestBlip().numReplies()); assertEquals(0, first.getManifestBlip().getReply(0).numBlips()); // Still there after the next mutation. ObservableConversationBlip second = target.getRootThread().appendBlip(); assertThreadValid(replyThread); assertEquals(Arrays.asList(replyThread), CollectionUtils.newArrayList(first.getReplyThreads())); verify(convListener).onBlipAdded(second); verifyNoMoreInteractions(blipListener, threadListener, convListener); }
public void testConcrrentDeletionOfFinalBlipsLeavesEmptyThread() { WaveletBasedConversationBlip first = target.getRootThread().appendBlip(); WaveletBasedConversationThread replyThread = first.addReplyThread(); WaveletBasedConversationBlip b1 = replyThread.appendBlip(); WaveletBasedConversationBlip b2 = replyThread.appendBlip(); // Locally delete b1, remotely delete b2. b1.delete(); replyThread.addListener(threadListener); b2.addListener(blipListener); target.addListener(convListener); remoteRemoveBlip(b2); // Expect blip deletion events and it to be invalid. verify(blipListener).onDeleted(); verify(convListener).onBlipDeleted(b2); assertBlipInvalid(b2); assertThreadValid(replyThread); assertEquals(Arrays.asList(replyThread), CollectionUtils.newArrayList(first.getReplyThreads())); // The manifest now has a thread with no blips. assertEquals(1, first.getManifestBlip().numReplies()); assertEquals(0, first.getManifestBlip().getReply(0).numBlips()); // Still there after the next mutation. ObservableConversationBlip second = target.getRootThread().appendBlip(); assertThreadValid(replyThread); assertEquals(Arrays.asList(replyThread), CollectionUtils.newArrayList(first.getReplyThreads())); verify(convListener).onBlipAdded(second); verifyNoMoreInteractions(blipListener, threadListener, convListener); }