1 package org.collectionspace.services.common.vocabulary;
3 import java.util.Iterator;
7 import org.collectionspace.services.client.PoxPayloadIn;
8 import org.collectionspace.services.client.PoxPayloadOut;
9 import org.collectionspace.services.common.context.ServiceContext;
10 import org.collectionspace.services.common.document.DocumentException;
11 import org.collectionspace.services.common.document.DocumentNotFoundException;
12 import org.collectionspace.services.common.repository.RepositoryClient;
13 import org.collectionspace.services.common.vocabulary.RefNameServiceUtils.AuthRefConfigInfo;
14 import org.collectionspace.services.config.service.ServiceBindingType;
15 import org.collectionspace.services.nuxeo.client.java.RepositoryInstanceInterface;
17 import org.nuxeo.ecm.core.api.DocumentModel;
18 import org.nuxeo.ecm.core.api.DocumentModelList;
19 import org.nuxeo.ecm.core.api.impl.DocumentModelListImpl;
20 import org.nuxeo.ecm.core.api.repository.RepositoryInstance;
22 import com.google.common.collect.AbstractIterator;
25 * A DocumentModelList representing all of the documents that potentially reference an
26 * authority item, found via full text search. This list must be post-processed to
27 * eliminate false positives.
29 * Documents in this list are lazily fetched one page at a time, as they are accessed through
30 * the list's Iterator, retrieved with the iterator() method. List items may not be accessed
31 * through any other means, including the get() method, and the ListIterator retrieved
32 * with listIterator(). Attempts to do so will result in unspecified behavior.
35 public class LazyAuthorityRefDocList extends DocumentModelListImpl {
36 private static final long serialVersionUID = 1L;
38 private ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx;
39 private RepositoryClient<PoxPayloadIn, PoxPayloadOut> repoClient;
40 private RepositoryInstanceInterface repoSession;
41 private List<String> serviceTypes;
42 private String refName;
43 private String refPropName;
44 private Map<String, ServiceBindingType> queriedServiceBindings;
45 private Map<String, List<AuthRefConfigInfo>> authRefFieldsByService;
46 private String whereClauseAdditions;
47 private String orderByClause;
50 private DocumentModelList firstPageDocList;
53 * Creates a LazyAuthorityRefDocList. The method signature is modeled after
54 * RefNameServiceUtils.findAuthorityRefDocs (the non-lazy way of doing this).
62 * @param queriedServiceBindings
63 * @param authRefFieldsByService
64 * @param whereClauseAdditions
65 * @param orderByClause
66 * @param pageSize The number of documents to retrieve in each page
68 * @throws DocumentException
69 * @throws DocumentNotFoundException
71 public LazyAuthorityRefDocList(
72 ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx,
73 RepositoryClient<PoxPayloadIn, PoxPayloadOut> repoClient,
74 RepositoryInstanceInterface repoSession, List<String> serviceTypes,
77 Map<String, ServiceBindingType> queriedServiceBindings,
78 Map<String, List<AuthRefConfigInfo>> authRefFieldsByService,
79 String whereClauseAdditions,
82 boolean computeTotal) throws DocumentException, DocumentNotFoundException {
85 this.repoClient = repoClient;
86 this.repoSession = repoSession;
87 this.serviceTypes = serviceTypes;
88 this.refName = refName;
89 this.refPropName = refPropName;
90 this.queriedServiceBindings = queriedServiceBindings;
91 this.authRefFieldsByService = authRefFieldsByService;
92 this.whereClauseAdditions = whereClauseAdditions;
93 this.orderByClause = orderByClause;
94 this.pageSize = pageSize;
96 // Fetch the first page immediately. This is necessary so that calls
97 // to totalSize() will work immediately. The computeTotal flag is passed
98 // into this initial page fetch. There's no need to compute totals
99 // when fetching subsequent pages.
101 firstPageDocList = fetchPage(0, computeTotal);
105 * Retrieves a page of authority references.
107 * @param pageNum The page number
108 * @param computeTotal
110 * @throws DocumentNotFoundException
111 * @throws DocumentException
113 private DocumentModelList fetchPage(int pageNum, boolean computeTotal) throws DocumentNotFoundException, DocumentException {
114 return RefNameServiceUtils.findAuthorityRefDocs(ctx, repoClient, repoSession,
115 serviceTypes, refName, refPropName, queriedServiceBindings, authRefFieldsByService,
116 whereClauseAdditions, orderByClause, pageSize, pageNum, computeTotal);
120 public long totalSize() {
121 // Return the totalSize from the first page of documents.
122 return firstPageDocList.totalSize();
126 public Iterator<DocumentModel> iterator() {
127 // Create a new iterator that starts with the first page of documents.
128 return new Itr(0, firstPageDocList);
132 * An iterator over a LazyAuthorityRefDocList. The iterator keeps one
133 * page of documents in memory at a time, and traverses that page until
134 * no items remain. A new page is fetched only when the current page is
138 private class Itr extends AbstractIterator<DocumentModel> {
139 private int currentPageNum = 0;
140 private DocumentModelList currentPageDocList;
141 private Iterator<DocumentModel> currentPageIterator;
144 * Creates a new iterator.
146 * @param currentPageNum The initial page number
147 * @param currentPageDocList The documents in the initial page
149 protected Itr(int pageNum, DocumentModelList pageDocList) {
150 setCurrentPage(pageNum, pageDocList);
154 * Changes the current page.
156 * @param pageNum The new page number
157 * @param pageDocList The documents in the new page
159 private void setCurrentPage(int pageNum, DocumentModelList pageDocList) {
160 this.currentPageNum = pageNum;
161 this.currentPageDocList = pageDocList;
162 this.currentPageIterator = pageDocList.iterator();
166 protected DocumentModel computeNext() {
167 // Find the next document to return, looking first in the current
168 // page. If the current page is exhausted, fetch the next page.
170 if (currentPageIterator.hasNext()) {
171 // There is still an element to return from the current page.
172 return currentPageIterator.next();
175 // The current page is exhausted.
177 if (pageSize == 0 || (currentPageDocList.size() < pageSize)) {
178 // There are no more pages.
182 // There may be more pages. Try to fetch the next one.
184 int nextPageNum = currentPageNum + 1;
185 DocumentModelList nextPageDocList = null;
188 nextPageDocList = fetchPage(nextPageNum, false);
190 catch(DocumentException e) {}
192 if (nextPageDocList == null || nextPageDocList.size() == 0) {
193 // There are no more pages.
197 // There is another page. Make it the current page.
199 setCurrentPage(nextPageNum, nextPageDocList);
201 if (currentPageIterator.hasNext()) {
202 return currentPageIterator.next();
205 // Shouldn't get here.