/* * Copyright (c) 2009-2010 Lockheed Martin Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.eurekastreams.server.search.stream; import java.util.ArrayList; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Intersects two sorted lists of Longs to build a page of data. The source list is requested a page at a time, and the * second list is requested in its entirety. */ public class SearchResultListScoper implements PageFetcher<Long> { /** * The logger. */ private Log log = LogFactory.getLog(SearchResultListScoper.class); /** * The PageFetcher to pull the first list of Longs. */ private PageFetcher<Long> searchResultsFetcher; /** * The PageFetcher to pull the second list of Longs. */ private PageFetcher<Long> availableIdsFetcher; /** * The page size for the search results. */ private int searchResultPageSize; /** * Constructor. * * @param inSearchResultsFetcher * the PageFetcher to get the search results * @param inAvailableIdsFetcher * the PageFetcher get the list of available ids * @param inSearchResultPageSize * the search result page size * @param inLastSeenActivityId * the last activity id that the user has seen - return results with ids less than this */ public SearchResultListScoper(final PageFetcher<Long> inSearchResultsFetcher, final PageFetcher<Long> inAvailableIdsFetcher, final int inSearchResultPageSize, final Long inLastSeenActivityId) { searchResultsFetcher = inSearchResultsFetcher; availableIdsFetcher = inAvailableIdsFetcher; searchResultPageSize = inSearchResultPageSize; } /** * Fetch a page of results by intersecting a source list of Longs with a second list of Longs. * * @param inStartIndex * the starting index of the page to fetch * @param inPageSize * the size of the page to build * @return an intersection of two lists of Longs */ @Override public List<Long> fetchPage(final int inStartIndex, final int inPageSize) { int searchResultListIndex = 0; // we fetch the entire second list of IDs in one request if (log.isTraceEnabled()) { log.trace("Loading up all of the available activity IDs for searching"); } List<Long> availableIDs = availableIdsFetcher.fetchPage(0, Integer.MAX_VALUE); if (log.isTraceEnabled()) { log.trace("Loaded up all the available activity IDs for searching."); } // the list of results List<Long> results = new ArrayList<Long>(); if (availableIDs == null || availableIDs.size() == 0) { log.trace("no available activity IDs - don't bother searching, just return empty list"); return results; } if (log.isTraceEnabled()) { log.trace("Begin security scoping to fetch page."); if (log.isTraceEnabled()) { log.trace("Available IDs to be scoped: " + availableIDs.toString()); } } // the point we last checked the second list int nextListBIndex = 0; // loop across the source list, finding those that are in the second // list List<Long> sourceList = null; do { if (log.isTraceEnabled()) { log.trace("Fetching page of search results with index: " + searchResultListIndex + " and page size: " + searchResultPageSize); } // get a page of results from the source sourceList = searchResultsFetcher.fetchPage(searchResultListIndex, searchResultPageSize); if (log.isTraceEnabled()) { log.trace("Fetched page of search results for scoping with ids: " + sourceList.toString()); } // loop across each ID in the page of source IDs for (Long sourceId : sourceList) { // search for this source ID in the second list, but stop // looking for the source ID if it's newer than // the second id for (int listBIndex = nextListBIndex; // line break sourceId <= availableIDs.get(listBIndex); nextListBIndex++, listBIndex++) { if (sourceId.equals(availableIDs.get(listBIndex))) { results.add(sourceId); if (results.size() == inPageSize) { // we have a full page of results if (log.isTraceEnabled()) { log.trace("Finished security scoping to fetch page - returning results: " + results.toString()); } return results; } } if (listBIndex == availableIDs.size() - 1) { // we've hit the end of list B - we're done if (log.isTraceEnabled()) { log.trace("Finished security scoping to fetch page - returning results: " + results.toString()); } return results; } } } searchResultListIndex += searchResultPageSize; } while (sourceList.size() == searchResultPageSize); // stop looping if // our last page // request didn't // get a full // page if (log.isTraceEnabled()) { log.trace("Finished security scoping to fetch page - returning results: " + results.toString()); } return results; } }