CombinedMaster implements AbstractMaster<D> { protected void search(List<? extends AbstractSearchResult<D>> results, final SearchCallback<D, M> callback) { final Set<D> nonUnique = new HashSet<D>(); List<ListIterator<D>> iterators = Lists.newArrayList(); Set<Integer> nextIteratorsToUse = Sets.newHashSet(); for (AbstractSearchResult<D> searchResult : results) { final List<D> documents = (searchResult != null) ? getNonUnique(nonUnique, searchResult.getDocuments(), callback) : Collections.<D>emptyList(); iterators.add(documents.listIterator()); nextIteratorsToUse.add(iterators.size() - 1); } int remainingIterators = iterators.size(); List<IndexedElement> elements = Lists.newArrayList(); do { remainingIterators = refillElements(elements, callback, iterators, nextIteratorsToUse, remainingIterators); assert remainingIterators >= 0; if (remainingIterators < 0) { s_logger.error("Illegal state - number of remaining iterators is negative."); } if (remainingIterators <= 0) { break; } Collections.sort(elements, Ordering.natural().reverse()); ListIterator<IndexedElement> it = elements.listIterator(elements.size()); List<IndexedElement> elementResults = Lists.newLinkedList(); while (true) { IndexedElement indexedElement = it.previous(); it.remove(); elementResults.add(indexedElement); int index = indexedElement._index; nextIteratorsToUse.add(index); if (!it.hasPrevious()) { break; } D document = indexedElement._element; IndexedElement peekedElement = elements.get(elements.size() - 1); if (callback.compare(document, peekedElement._element) != 0) { break; } }; if (elementResults.size() == 1) { IndexedElement indexedElement = elementResults.get(0); callback.accept(indexedElement._element, _masterList.get(indexedElement._index), true, true); } else { boolean uniqueAcrossMasters = nextIteratorsToUse.size() == 1; for (IndexedElement element : elementResults) { boolean uniqueWithinMaster = !nonUnique.contains(element._element); callback.accept(element._element, _masterList.get(element._index), uniqueWithinMaster, uniqueAcrossMasters); } } } while (true); } protected  CombinedMaster(List<M> masterList); @Override D get(final UniqueId uniqueId); @Override D get(final ObjectIdentifiable objectId, final VersionCorrection versionCorrection); @Override D add(final D document); @Override D update(final D document); @Override void remove(final ObjectIdentifiable objectIdentifiable); @Override D correct(final D document); @Override final List<UniqueId> replaceVersion(final UniqueId uniqueId, final List<D> replacementDocuments); @Override final List<UniqueId> replaceAllVersions(final ObjectIdentifiable objectId, final List<D> replacementDocuments); @Override List<UniqueId> replaceVersions(final ObjectIdentifiable objectId, final List<D> replacementDocuments); @Override final void removeVersion(final UniqueId uniqueId); @Override final UniqueId replaceVersion(D replacementDocument); @Override final UniqueId addVersion(ObjectIdentifiable objectId, D documentToAdd); @Override Map<UniqueId, D> get(Collection<UniqueId> uniqueIds);  }
@Test public void search() { HolidayDocument m1h1 = holidayDocWithId("m1", "1"); HolidayDocument m1h2 = holidayDocWithId("m1", "2"); HolidayDocument m1h3 = holidayDocWithId("m1", "3"); HolidayDocument m1h4 = holidayDocWithId("m1", "4"); HolidayDocument m2h3 = holidayDocWithId("m2", "3"); HolidayDocument m2h4 = holidayDocWithId("m2", "4"); HolidayDocument m2h5 = holidayDocWithId("m2", "5"); HolidayDocument m2h6 = holidayDocWithId("m2", "6"); final HolidayDocument m2h7 = holidayDocWithId("m2", "7"); HolidaySearchResult m1Result = new HolidaySearchResult(Lists.newArrayList(m1h1, m1h2, m1h2, m1h3, m1h4, m1h4)); HolidaySearchResult m2Result = new HolidaySearchResult(Lists.newArrayList(m2h3, m2h4, m2h5, m2h6, m2h7)); final List<HolidayDocument> resultList = Lists.newArrayList(); @SuppressWarnings("unchecked") final SearchCallback<HolidayDocument, HolidayMaster> cbDelegate = mock(SearchCallback.class); cMaster.search(Lists.newArrayList(m1Result, m2Result, null), new SearchCallback<HolidayDocument, HolidayMaster>() { @Override public int compare(HolidayDocument arg0, HolidayDocument arg1) { return arg0.getUniqueId().getValue().compareTo(arg1.getUniqueId().getValue()); } @Override public boolean include(HolidayDocument document) { return !m2h7.equals(document); } @Override public void accept(HolidayDocument document, HolidayMaster master, boolean masterUnique, boolean clientUnique) { cbDelegate.accept(document, master, masterUnique, clientUnique); resultList.add(document); } }); verify(cbDelegate).accept(m1h1, m1, true, true); verify(cbDelegate, times(2)).accept(m1h2, m1, false, true); verify(cbDelegate).accept(m1h3, m1, true, false); verify(cbDelegate).accept(m2h3, m2, true, false); verify(cbDelegate, times(2)).accept(m1h4, m1, false, false); verify(cbDelegate).accept(m2h4, m2, true, false); verify(cbDelegate).accept(m2h5, m2, true, true); verify(cbDelegate).accept(m2h6, m2, true, true); verifyNoMoreInteractions(cbDelegate); ArrayList<HolidayDocument> sortedResultList = Lists.newArrayList(resultList); Collections.sort(sortedResultList, cbDelegate); assertEquals(sortedResultList, resultList); }