diff --git a/source/java/org/alfresco/cmis/mapping/BaseCMISTest.java b/source/java/org/alfresco/cmis/mapping/BaseCMISTest.java index 3eaba682c9..dc0ddbe9c4 100644 --- a/source/java/org/alfresco/cmis/mapping/BaseCMISTest.java +++ b/source/java/org/alfresco/cmis/mapping/BaseCMISTest.java @@ -46,6 +46,7 @@ import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.cmr.security.AuthenticationService; +import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.ApplicationContextHelper; @@ -96,6 +97,8 @@ public abstract class BaseCMISTest extends TestCase protected ContentService contentService; + protected PermissionService permissionService; + public void setUp() throws Exception { serviceRegistry = (ServiceRegistry) ctx.getBean("ServiceRegistry"); @@ -116,6 +119,8 @@ public abstract class BaseCMISTest extends TestCase contentService = (ContentService) ctx.getBean("contentService"); + permissionService = (PermissionService) ctx.getBean("permissionService"); + authenticationService = (AuthenticationService) ctx.getBean("authenticationService"); authenticationDAO = (MutableAuthenticationDao) ctx.getBean("authenticationDao"); diff --git a/source/java/org/alfresco/cmis/search/CMISResultSetImpl.java b/source/java/org/alfresco/cmis/search/CMISResultSetImpl.java index ccb5e72a47..018bae4df2 100644 --- a/source/java/org/alfresco/cmis/search/CMISResultSetImpl.java +++ b/source/java/org/alfresco/cmis/search/CMISResultSetImpl.java @@ -63,11 +63,11 @@ public class CMISResultSetImpl implements CMISResultSet, Serializable Query query; CMISDictionaryService cmisDictionaryService; - + DictionaryService alfrescoDictionaryService; - - public CMISResultSetImpl(Map wrapped, CMISQueryOptions options, NodeService nodeService, Query query, CMISDictionaryService cmisDictionaryService, DictionaryService alfrescoDictionaryService) + public CMISResultSetImpl(Map wrapped, CMISQueryOptions options, NodeService nodeService, Query query, CMISDictionaryService cmisDictionaryService, + DictionaryService alfrescoDictionaryService) { this.wrapped = wrapped; this.options = options; @@ -125,17 +125,10 @@ public class CMISResultSetImpl implements CMISResultSet, Serializable { for (ResultSet resultSet : wrapped.values()) { - if (resultSet.getResultSetMetaData().getLimitedBy() != LimitBy.UNLIMITED) + if (resultSet.hasMore()) { return true; } - else - { - if(resultSet.length() - getStart() > getLength() ) - { - return true; - } - } } return false; } @@ -149,16 +142,7 @@ public class CMISResultSetImpl implements CMISResultSet, Serializable { for (ResultSet resultSet : wrapped.values()) { - int max = options.getMaxItems(); - int skip = options.getSkipCount(); - if((max >= 0) && (max < (resultSet.length() - skip))) - { - return options.getMaxItems(); - } - else - { - return resultSet.length() - skip; - } + return resultSet.length(); } throw new IllegalStateException(); } @@ -189,7 +173,7 @@ public class CMISResultSetImpl implements CMISResultSet, Serializable for (String selector : wrapped.keySet()) { ResultSet rs = wrapped.get(selector); - refs.put(selector, rs.getNodeRef(getStart() + i)); + refs.put(selector, rs.getNodeRef(i)); } return refs; } @@ -200,7 +184,7 @@ public class CMISResultSetImpl implements CMISResultSet, Serializable for (String selector : wrapped.keySet()) { ResultSet rs = wrapped.get(selector); - scores.put(selector, Float.valueOf(rs.getScore(getStart() + i))); + scores.put(selector, Float.valueOf(rs.getScore(i))); } return scores; } @@ -211,8 +195,6 @@ public class CMISResultSetImpl implements CMISResultSet, Serializable return nodeService.getPrimaryParent(nodeRef); } - - public List getChildAssocRefs() { ArrayList cars = new ArrayList(length()); @@ -226,7 +208,7 @@ public class CMISResultSetImpl implements CMISResultSet, Serializable public NodeRef getNodeRef(int n) { Map refs = getNodeRefs(n); - if(refs.size() == 1) + if (refs.size() == 1) { return refs.values().iterator().next(); } @@ -253,15 +235,15 @@ public class CMISResultSetImpl implements CMISResultSet, Serializable public float getScore(int n) { - Map scores = getScores(n); - if(scores.size() == 1) - { - return scores.values().iterator().next(); - } - else - { - throw new IllegalStateException("Ambiguous selector"); - } + Map scores = getScores(n); + if (scores.size() == 1) + { + return scores.values().iterator().next(); + } + else + { + throw new IllegalStateException("Ambiguous selector"); + } } public int length() diff --git a/source/java/org/alfresco/cmis/search/QueryTest.java b/source/java/org/alfresco/cmis/search/QueryTest.java index f27649bd09..00ab78643b 100644 --- a/source/java/org/alfresco/cmis/search/QueryTest.java +++ b/source/java/org/alfresco/cmis/search/QueryTest.java @@ -54,6 +54,7 @@ import org.alfresco.service.cmr.repository.MLText; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter; import org.alfresco.service.cmr.repository.datatype.Duration; +import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.namespace.QName; import org.alfresco.util.CachingDateFormat; import org.antlr.runtime.ANTLRStringStream; @@ -77,10 +78,14 @@ public class QueryTest extends BaseCMISTest public void setUp() throws Exception { super.setUp(); - + + f0 = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName("cm", "Folder 0", namespaceService), ContentModel.TYPE_FOLDER).getChildRef(); nodeService.setProperty(f0, ContentModel.PROP_NAME, "Folder 0"); folder_count++; + + permissionService.setPermission(f0, "cmis", PermissionService.READ, true); + NodeRef f1 = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, QName.createQName("cm", "Folder 1", namespaceService), ContentModel.TYPE_FOLDER) .getChildRef(); @@ -1593,6 +1598,13 @@ public class QueryTest extends BaseCMISTest testQuery("SELECT * FROM Document", 0, false, "ObjectId", new String(), false); } + + public void testBasicSelectAsCmis() + { + runAs("cmis"); + testQuery("SELECT * FROM Document", 7, false, "ObjectId", new String(), false); + + } public void testBasicSelect() { diff --git a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneSearcherImpl.java b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneSearcherImpl.java index 00a950c687..79b1bb2ff1 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneSearcherImpl.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneSearcherImpl.java @@ -433,6 +433,7 @@ public class ADMLuceneSearcherImpl extends AbstractLuceneBase implements LuceneS } ResultSet rs = new LuceneResultSet(hits, searcher, nodeService, tenantService, searchParameters, getLuceneConfig()); + rs = new PagingLuceneResultSet(rs, searchParameters, nodeService); if (getLuceneConfig().getPostSortDateTime() && requiresPostSort) { ResultSet sorted = new SortedResultSet(rs, nodeService, searchParameters, namespacePrefixResolver); @@ -474,7 +475,9 @@ public class ADMLuceneSearcherImpl extends AbstractLuceneBase implements LuceneS return new EmptyResultSet(); } Hits hits = searcher.search(query); - return new LuceneResultSet(hits, searcher, nodeService, tenantService, searchParameters, getLuceneConfig()); + ResultSet rs = new LuceneResultSet(hits, searcher, nodeService, tenantService, searchParameters, getLuceneConfig()); + rs = new PagingLuceneResultSet(rs, searchParameters, nodeService); + return rs; } catch (SAXPathException e) { diff --git a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneTest.java b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneTest.java index fb0504512c..bb736a4379 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneTest.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneTest.java @@ -38,15 +38,23 @@ import java.util.Date; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Random; +import javax.transaction.HeuristicMixedException; +import javax.transaction.HeuristicRollbackException; +import javax.transaction.RollbackException; import javax.transaction.Status; +import javax.transaction.SystemException; import javax.transaction.UserTransaction; import junit.framework.TestCase; +import org.alfresco.cmis.CMISQueryOptions; +import org.alfresco.cmis.CMISResultSet; +import org.alfresco.cmis.CMISResultSetRow; import org.alfresco.i18n.I18NUtil; import org.alfresco.model.ContentModel; import org.alfresco.repo.dictionary.DictionaryDAO; @@ -88,6 +96,7 @@ import org.alfresco.service.cmr.repository.datatype.Duration; import org.alfresco.service.cmr.search.QueryParameter; import org.alfresco.service.cmr.search.QueryParameterDefinition; import org.alfresco.service.cmr.search.ResultSet; +import org.alfresco.service.cmr.search.ResultSetMetaData; import org.alfresco.service.cmr.search.ResultSetRow; import org.alfresco.service.cmr.search.SearchParameters; import org.alfresco.service.cmr.search.SearchService; @@ -641,6 +650,147 @@ public class ADMLuceneTest extends TestCase } + public void testPublicServiceSearchServicePaging() throws Exception + { + testTX.commit(); + testTX = transactionService.getUserTransaction(); + testTX.begin(); + + List expected = new ArrayList(15); + + SearchParameters sp = new SearchParameters(); + sp.setLanguage(SearchService.LANGUAGE_FTS_ALFRESCO); + sp.setQuery("PATH:\"//.\""); + sp.addStore(rootNodeRef.getStoreRef()); + sp.excludeDataInTheCurrentTransaction(true); + + ResultSet results; + ResultSetMetaData md; + + results = serviceRegistry.getSearchService().query(sp); + assertEquals(15, results.length()); + md = results.getResultSetMetaData(); + for (ResultSetRow row : results) + { + expected.add(row.getNodeRef()); + } + results.close(); + for (int skip = 0; skip < 20; skip++) + { + for (int max = 0; max < 20; max++) + { + doPage(expected, skip, max, sp, serviceRegistry.getSearchService()); + } + } + + this.authenticationComponent.setCurrentUser("admin"); + sp = new SearchParameters(); + sp.setLanguage(SearchService.LANGUAGE_LUCENE); + sp.setQuery("PATH:\"//.\""); + sp.addStore(rootNodeRef.getStoreRef()); + sp.excludeDataInTheCurrentTransaction(true); + + results = serviceRegistry.getSearchService().query(sp); + assertEquals(15, results.length()); + results.close(); + + sp.setMaxPermissionChecks(2); + results = serviceRegistry.getSearchService().query(sp); + assertEquals(2, results.length()); + results.close(); + + sp.setLanguage(SearchService.LANGUAGE_FTS_ALFRESCO); + sp.setMaxPermissionChecks(2); + results = serviceRegistry.getSearchService().query(sp); + assertEquals(2, results.length()); + results.close(); + + // Even though it is picked up they go though before the time moves on + // sp.setMaxPermissionChecks(-1); + // sp.setMaxPermissionCheckTimeMillis(0); + // results = serviceRegistry.getSearchService().query(sp); + // assertEquals(0, results.length()); + // results.close(); + + } + + private void doPage(List expected, int skip, int max, SearchParameters sp, SearchService searcher) + { + sp.setSkipCount(skip); + sp.setMaxItems(max); + ResultSet results = searcher.query(sp); + assertEquals("Skip = " + skip + " max = " + max, skip + max > 15 ? 15 - skip : max, results.length()); + assertEquals("Skip = " + skip + " max = " + max, (skip + max) < 15, results.hasMore()); + assertEquals("Skip = " + skip + " max = " + max, skip, results.getStart()); + int actualPosition = skip; + for (ResultSetRow row : results) + { + NodeRef nodeRef = row.getNodeRef(); + assertEquals("Skip = " + skip + " max = " + max + " actual = " + actualPosition, expected.get(actualPosition), nodeRef); + actualPosition++; + } + } + + public void testNonPublicSearchServicePaging() throws InterruptedException + { + luceneFTS.pause(); + buildBaseIndex(); + + ADMLuceneSearcherImpl searcher = ADMLuceneSearcherImpl.getSearcher(rootNodeRef.getStoreRef(), indexerAndSearcher); + searcher.setNodeService(nodeService); + searcher.setDictionaryService(dictionaryService); + searcher.setTenantService(tenantService); + searcher.setNamespacePrefixResolver(getNamespacePrefixReolsver("namespace")); + searcher.setQueryRegister(queryRegisterComponent); + searcher.setQueryLanguages(((AbstractLuceneIndexerAndSearcherFactory) indexerAndSearcher).queryLanguages); + + List expected = new ArrayList(15); + + SearchParameters sp = new SearchParameters(); + sp.setLanguage(SearchService.LANGUAGE_FTS_ALFRESCO); + sp.setQuery("PATH:\"//.\""); + sp.addStore(rootNodeRef.getStoreRef()); + sp.excludeDataInTheCurrentTransaction(true); + + ResultSet results; + ResultSetMetaData md; + + results = searcher.query(sp); + assertEquals(15, results.length()); + md = results.getResultSetMetaData(); + for (ResultSetRow row : results) + { + expected.add(row.getNodeRef()); + } + results.close(); + + for (int skip = 0; skip < 20; skip++) + { + for (int max = 0; max < 20; max++) + { + doPage(expected, skip, max, sp, searcher); + } + } + + } + + private void doPage(List expected, int skip, int max, SearchParameters sp, ADMLuceneSearcherImpl searcher) + { + sp.setSkipCount(skip); + sp.setMaxItems(max); + ResultSet results = searcher.query(sp); + assertEquals("Skip = " + skip + " max = " + max, skip + max > 15 ? 15 - skip : max, results.length()); + assertEquals("Skip = " + skip + " max = " + max, (skip + max) < 15, results.hasMore()); + assertEquals("Skip = " + skip + " max = " + max, skip, results.getStart()); + int actualPosition = skip; + for (ResultSetRow row : results) + { + NodeRef nodeRef = row.getNodeRef(); + assertEquals("Skip = " + skip + " max = " + max + " actual = " + actualPosition, expected.get(actualPosition), nodeRef); + actualPosition++; + } + } + public void testAlfrescoSql() throws InterruptedException { luceneFTS.pause(); @@ -657,7 +807,7 @@ public class ADMLuceneTest extends TestCase alfrescoSqlQueryWithCount(searcher, "SELECT * FROM DOCUMENT", 1); alfrescoSqlQueryWithCount(searcher, "SELECT * FROM DOCUMENT D JOIN CM_OWNABLE O ON (D.OBJECTID = O.OBJECTID)", 0); } - + public void alfrescoSqlQueryWithCount(ADMLuceneSearcherImpl searcher, String query, int count) { ResultSet results = searcher.query(rootNodeRef.getStoreRef(), SearchService.LANGUAGE_SQL_ALFTRESCO, query, null); @@ -665,7 +815,7 @@ public class ADMLuceneTest extends TestCase results.getResultSetMetaData(); results.close(); } - + public void testCmisSql() throws InterruptedException { luceneFTS.pause(); @@ -682,7 +832,7 @@ public class ADMLuceneTest extends TestCase sqlQueryWithCount(searcher, "SELECT * FROM DOCUMENT", 1); sqlQueryWithCount(searcher, "SELECT * FROM DOCUMENT D WHERE CONTAINS(D,'lazy')", 1); } - + public void sqlQueryWithCount(ADMLuceneSearcherImpl searcher, String query, int count) { ResultSet results = searcher.query(rootNodeRef.getStoreRef(), SearchService.LANGUAGE_SQL_CMIS_STRICT, query, null); @@ -690,7 +840,7 @@ public class ADMLuceneTest extends TestCase results.getResultSetMetaData(); results.close(); } - + public void testFTS() throws InterruptedException { luceneFTS.pause(); @@ -785,7 +935,7 @@ public class ADMLuceneTest extends TestCase ftsQueryWithCount(searcher, "TEXT:(brown *(6) dog)", 1); // ftsQueryWithCount(searcher, "brown..dog", 1); // is this allowed?? - //ftsQueryWithCount(searcher, "cm:content:brown..dog", 1); + // ftsQueryWithCount(searcher, "cm:content:brown..dog", 1); QName qname = QName.createQName(TEST_NAMESPACE, "float\\-ista"); ftsQueryWithCount(searcher, qname + ":3.40", 1); @@ -887,26 +1037,26 @@ public class ADMLuceneTest extends TestCase ftsQueryWithCount(searcher, "lazy -lazy", 15, null, n14); ftsQueryWithCount(searcher, "lazy^20 -lazy", 15, n14, null); ftsQueryWithCount(searcher, "lazy^20 -lazy^20", 15, null, n14); - + ftsQueryWithCount(searcher, "cm:content:lazy", 1); // Simple template ftsQueryWithCount(searcher, "ANDY:lazy", 1); // default namesapce cm ftsQueryWithCount(searcher, "content:lazy", 1); - - + ftsQueryWithCount(searcher, "PATH:\"//.\"", 15); - + ftsQueryWithCount(searcher, "+PATH:\"/app:company_home/st:sites/cm:rmtestnew1/cm:documentLibrary//*\"", 0); ftsQueryWithCount(searcher, "+PATH:\"/app:company_home/st:sites/cm:rmtestnew1/cm:documentLibrary//*\" -TYPE:\"{http://www.alfresco.org/model/content/1.0}thumbnail\"", 15); - ftsQueryWithCount(searcher, "+PATH:\"/app:company_home/st:sites/cm:rmtestnew1/cm:documentLibrary//*\" AND -TYPE:\"{http://www.alfresco.org/model/content/1.0}thumbnail\"", 0); + ftsQueryWithCount(searcher, "+PATH:\"/app:company_home/st:sites/cm:rmtestnew1/cm:documentLibrary//*\" AND -TYPE:\"{http://www.alfresco.org/model/content/1.0}thumbnail\"", + 0); } public void ftsQueryWithCount(ADMLuceneSearcherImpl searcher, String query, int count) { SearchParameters sp = new SearchParameters(); - sp.setLanguage( SearchService.LANGUAGE_FTS_ALFRESCO); + sp.setLanguage(SearchService.LANGUAGE_FTS_ALFRESCO); sp.addStore(rootNodeRef.getStoreRef()); sp.setQuery(query); sp.addQueryTemplate("ANDY", "%cm:content"); @@ -920,18 +1070,18 @@ public class ADMLuceneTest extends TestCase public void ftsQueryWithCount(ADMLuceneSearcherImpl searcher, String query, int count, NodeRef first, NodeRef last) { ResultSet results = searcher.query(rootNodeRef.getStoreRef(), SearchService.LANGUAGE_FTS_ALFRESCO, query, null); - for(ResultSetRow row : results) + for (ResultSetRow row : results) { - System.out.println(""+ row.getScore() + nodeService.getProperty(row.getNodeRef(), ContentModel.PROP_NAME)); + System.out.println("" + row.getScore() + nodeService.getProperty(row.getNodeRef(), ContentModel.PROP_NAME)); } assertEquals(count, results.length()); if (first != null) { assertEquals(first, results.getNodeRef(0)); } - if(last != null) + if (last != null) { - assertEquals(last, results.getNodeRef(results.length()-1)); + assertEquals(last, results.getNodeRef(results.length() - 1)); } results.close(); } @@ -3599,14 +3749,12 @@ public class ADMLuceneTest extends TestCase results.close(); sDate = CachingDateFormat.getDateFormat().format(date); - results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "\\@" + escapeQName(QName.createQName(TEST_NAMESPACE, "datetime-ista")) + ":[MIN TO " + sDate + "]", - null); + results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "\\@" + escapeQName(QName.createQName(TEST_NAMESPACE, "datetime-ista")) + ":[MIN TO " + sDate + "]", null); assertEquals(1, results.length()); results.close(); sDate = CachingDateFormat.getDateFormat().format(date); - results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "\\@" + escapeQName(QName.createQName(TEST_NAMESPACE, "datetime-ista")) + ":[" + sDate + " TO MAX]", - null); + results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "\\@" + escapeQName(QName.createQName(TEST_NAMESPACE, "datetime-ista")) + ":[" + sDate + " TO MAX]", null); assertEquals(usesDateTimeAnalyser ? 0 : 1, results.length()); results.close(); @@ -3681,8 +3829,7 @@ public class ADMLuceneTest extends TestCase assertNotNull(results.getRow(0).getValue(QName.createQName(TEST_NAMESPACE, "any-many-ista"))); results.close(); - results = searcher - .query(rootNodeRef.getStoreRef(), "lucene", "\\@" + escapeQName(QName.createQName(TEST_NAMESPACE, "any-many-ista")) + ":\"anyValueAsString\"", null); + results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "\\@" + escapeQName(QName.createQName(TEST_NAMESPACE, "any-many-ista")) + ":\"anyValueAsString\"", null); assertEquals(1, results.length()); assertNotNull(results.getRow(0).getValue(QName.createQName(TEST_NAMESPACE, "any-many-ista"))); results.close(); @@ -3710,38 +3857,32 @@ public class ADMLuceneTest extends TestCase assertEquals(1, results.length()); results.close(); - results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "@" + LuceneQueryParser.escape(ContentModel.PROP_DESCRIPTION.toString()) + ":\"Alfresco Tutorial\"", - null); + results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "@" + LuceneQueryParser.escape(ContentModel.PROP_DESCRIPTION.toString()) + ":\"Alfresco Tutorial\"", null); assertEquals(1, results.length()); results.close(); - results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "@" + LuceneQueryParser.escape(ContentModel.PROP_DESCRIPTION.toString()) + ":\"Tutorial Alfresco\"", - null); + results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "@" + LuceneQueryParser.escape(ContentModel.PROP_DESCRIPTION.toString()) + ":\"Tutorial Alfresco\"", null); assertEquals(0, results.length()); results.close(); - results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "@" + LuceneQueryParser.escape(ContentModel.PROP_DESCRIPTION.toString()) + ":\"Tutorial Alfresco\"~0", - null); + results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "@" + LuceneQueryParser.escape(ContentModel.PROP_DESCRIPTION.toString()) + ":\"Tutorial Alfresco\"~0", null); assertEquals(0, results.length()); results.close(); - results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "@" + LuceneQueryParser.escape(ContentModel.PROP_DESCRIPTION.toString()) + ":\"Tutorial Alfresco\"~1", - null); + results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "@" + LuceneQueryParser.escape(ContentModel.PROP_DESCRIPTION.toString()) + ":\"Tutorial Alfresco\"~1", null); assertEquals(0, results.length()); results.close(); - results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "@" + LuceneQueryParser.escape(ContentModel.PROP_DESCRIPTION.toString()) + ":\"Tutorial Alfresco\"~2", - null); + results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "@" + LuceneQueryParser.escape(ContentModel.PROP_DESCRIPTION.toString()) + ":\"Tutorial Alfresco\"~2", null); assertEquals(1, results.length()); results.close(); - results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "@" + LuceneQueryParser.escape(ContentModel.PROP_DESCRIPTION.toString()) + ":\"Tutorial Alfresco\"~3", - null); + results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "@" + LuceneQueryParser.escape(ContentModel.PROP_DESCRIPTION.toString()) + ":\"Tutorial Alfresco\"~3", null); assertEquals(1, results.length()); results.close(); @@ -3880,13 +4021,12 @@ public class ADMLuceneTest extends TestCase results.close(); // Period - + results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "\\@" + escapeQName(QName.createQName(TEST_NAMESPACE, "period-ista")) + ":\"period|12\"", null); assertEquals(1, results.length()); assertNotNull(results.getRow(0).getValue(QName.createQName(TEST_NAMESPACE, "path-ista"))); results.close(); - // Type results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "TYPE:\"" + testType.toString() + "\"", null); @@ -4015,8 +4155,7 @@ public class ADMLuceneTest extends TestCase assertEquals(1, results.length()); results.close(); - results = searcher - .query(rootNodeRef.getStoreRef(), "lucene", "@" + LuceneQueryParser.escape(ContentModel.PROP_CONTENT.toString()) + ".mimetype:\"text/plain\"", null); + results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "@" + LuceneQueryParser.escape(ContentModel.PROP_CONTENT.toString()) + ".mimetype:\"text/plain\"", null); assertEquals(1, results.length()); results.close(); @@ -5129,7 +5268,7 @@ public class ADMLuceneTest extends TestCase // TODO: should not have a null property type definition QueryParameterDefImpl paramDef = new QueryParameterDefImpl(QName.createQName("alf:lemur", namespacePrefixResolver), (DataTypeDefinition) null, true, "fox"); - results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "TEXT:\"${alf:lemur}\"", new QueryParameterDefinition[] { paramDef }); + results = searcher.query(rootNodeRef.getStoreRef(), "lucene", "TEXT:\"${alf:lemur}\"", new QueryParameterDefinition[] { paramDef }); assertEquals(1, results.length()); results.close(); diff --git a/source/java/org/alfresco/repo/search/impl/lucene/LuceneAlfrescoFtsQueryLanguage.java b/source/java/org/alfresco/repo/search/impl/lucene/LuceneAlfrescoFtsQueryLanguage.java index 90a87bb205..39fa058c94 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/LuceneAlfrescoFtsQueryLanguage.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/LuceneAlfrescoFtsQueryLanguage.java @@ -45,13 +45,16 @@ public class LuceneAlfrescoFtsQueryLanguage implements LuceneQueryLanguageSPI options.setIncludeInTransactionData(!searchParameters.excludeDataInTheCurrentTransaction()); options.setDefaultFTSConnective(searchParameters.getDefaultOperator() == SearchParameters.Operator.OR ? Connective.OR : Connective.AND); options.setDefaultFTSFieldConnective(searchParameters.getDefaultOperator() == SearchParameters.Operator.OR ? Connective.OR : Connective.AND); + options.setSkipCount(searchParameters.getSkipCount()); + options.setMaxPermissionChecks(searchParameters.getMaxPermissionChecks()); + options.setMaxPermissionCheckTimeMillis(searchParameters.getMaxPermissionCheckTimeMillis()); if (searchParameters.getLimitBy() == LimitBy.FINAL_SIZE) { options.setMaxItems(searchParameters.getLimit()); } else { - options.setMaxItems(-1); + options.setMaxItems(searchParameters.getMaxItems()); } options.setMlAnalaysisMode(searchParameters.getMlAnalaysisMode()); options.setLocales(searchParameters.getLocales()); diff --git a/source/java/org/alfresco/repo/search/impl/lucene/LuceneAlfrescoSqlQueryLanguage.java b/source/java/org/alfresco/repo/search/impl/lucene/LuceneAlfrescoSqlQueryLanguage.java index 33afea8a03..ff5cb95129 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/LuceneAlfrescoSqlQueryLanguage.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/LuceneAlfrescoSqlQueryLanguage.java @@ -62,17 +62,20 @@ public class LuceneAlfrescoSqlQueryLanguage implements LuceneQueryLanguageSPI String sql = searchParameters.getQuery(); CMISQueryOptions options = new CMISQueryOptions(sql, searchParameters.getStores().get(0)); - options.setDefaultFTSConnective(searchParameters.getDefaultOperator() == SearchParameters.Operator.OR ? Connective.OR : Connective.AND); - options.setDefaultFTSFieldConnective(searchParameters.getDefaultOperator() == SearchParameters.Operator.OR ? Connective.OR : Connective.AND); options.setFetchSize(searchParameters.getBulkFecthSize()); options.setIncludeInTransactionData(!searchParameters.excludeDataInTheCurrentTransaction()); + options.setDefaultFTSConnective(searchParameters.getDefaultOperator() == SearchParameters.Operator.OR ? Connective.OR : Connective.AND); + options.setDefaultFTSFieldConnective(searchParameters.getDefaultOperator() == SearchParameters.Operator.OR ? Connective.OR : Connective.AND); + options.setSkipCount(searchParameters.getSkipCount()); + options.setMaxPermissionChecks(searchParameters.getMaxPermissionChecks()); + options.setMaxPermissionCheckTimeMillis(searchParameters.getMaxPermissionCheckTimeMillis()); if (searchParameters.getLimitBy() == LimitBy.FINAL_SIZE) { options.setMaxItems(searchParameters.getLimit()); } else { - options.setMaxItems(-1); + options.setMaxItems(searchParameters.getMaxItems()); } options.setMlAnalaysisMode(searchParameters.getMlAnalaysisMode()); options.setLocales(searchParameters.getLocales()); diff --git a/source/java/org/alfresco/repo/search/impl/lucene/LuceneCmisStrictSqlQueryLanguage.java b/source/java/org/alfresco/repo/search/impl/lucene/LuceneCmisStrictSqlQueryLanguage.java index 4497eb5d8f..46057640ea 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/LuceneCmisStrictSqlQueryLanguage.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/LuceneCmisStrictSqlQueryLanguage.java @@ -62,17 +62,20 @@ public class LuceneCmisStrictSqlQueryLanguage implements LuceneQueryLanguageSPI String sql = searchParameters.getQuery(); CMISQueryOptions options = new CMISQueryOptions(sql, searchParameters.getStores().get(0)); - options.setDefaultFTSConnective(searchParameters.getDefaultOperator() == SearchParameters.Operator.OR ? Connective.OR : Connective.AND); - options.setDefaultFTSFieldConnective(searchParameters.getDefaultOperator() == SearchParameters.Operator.OR ? Connective.OR : Connective.AND); options.setFetchSize(searchParameters.getBulkFecthSize()); options.setIncludeInTransactionData(!searchParameters.excludeDataInTheCurrentTransaction()); + options.setDefaultFTSConnective(searchParameters.getDefaultOperator() == SearchParameters.Operator.OR ? Connective.OR : Connective.AND); + options.setDefaultFTSFieldConnective(searchParameters.getDefaultOperator() == SearchParameters.Operator.OR ? Connective.OR : Connective.AND); + options.setSkipCount(searchParameters.getSkipCount()); + options.setMaxPermissionChecks(searchParameters.getMaxPermissionChecks()); + options.setMaxPermissionCheckTimeMillis(searchParameters.getMaxPermissionCheckTimeMillis()); if (searchParameters.getLimitBy() == LimitBy.FINAL_SIZE) { options.setMaxItems(searchParameters.getLimit()); } else { - options.setMaxItems(-1); + options.setMaxItems(searchParameters.getMaxItems()); } options.setMlAnalaysisMode(searchParameters.getMlAnalaysisMode()); options.setLocales(searchParameters.getLocales()); diff --git a/source/java/org/alfresco/repo/search/impl/lucene/LuceneResultSet.java b/source/java/org/alfresco/repo/search/impl/lucene/LuceneResultSet.java index 8637ad960f..09df3d9c1d 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/LuceneResultSet.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/LuceneResultSet.java @@ -32,12 +32,11 @@ import org.alfresco.repo.search.AbstractResultSet; import org.alfresco.repo.search.ResultSetRowIterator; import org.alfresco.repo.search.SearcherException; import org.alfresco.repo.search.SimpleResultSetMetaData; -import org.alfresco.repo.tenant.TenantService; import org.alfresco.repo.search.impl.lucene.index.CachingIndexReader; +import org.alfresco.repo.tenant.TenantService; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.cmr.repository.Path; import org.alfresco.service.cmr.search.LimitBy; import org.alfresco.service.cmr.search.PermissionEvaluationMode; import org.alfresco.service.cmr.search.ResultSetMetaData; diff --git a/source/java/org/alfresco/repo/search/impl/lucene/PagingLuceneResultSet.java b/source/java/org/alfresco/repo/search/impl/lucene/PagingLuceneResultSet.java new file mode 100644 index 0000000000..2b86181f45 --- /dev/null +++ b/source/java/org/alfresco/repo/search/impl/lucene/PagingLuceneResultSet.java @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.search.impl.lucene; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.alfresco.repo.search.impl.querymodel.Query; +import org.alfresco.service.cmr.dictionary.DictionaryService; +import org.alfresco.service.cmr.repository.ChildAssociationRef; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.search.LimitBy; +import org.alfresco.service.cmr.search.ResultSet; +import org.alfresco.service.cmr.search.ResultSetMetaData; +import org.alfresco.service.cmr.search.ResultSetRow; +import org.alfresco.service.cmr.search.SearchParameters; + +/** + * @author andyh + */ +public class PagingLuceneResultSet implements ResultSet, Serializable +{ + ResultSet wrapped; + + SearchParameters searchParameters; + + NodeService nodeService; + + public PagingLuceneResultSet(ResultSet wrapped, SearchParameters searchParameters, NodeService nodeService) + { + this.wrapped = wrapped; + this.searchParameters = searchParameters; + this.nodeService = nodeService; + } + + /* + * (non-Javadoc) + * + * @see org.alfresco.cmis.search.CMISResultSet#close() + */ + public void close() + { + wrapped.close(); + } + + /* + * (non-Javadoc) + * + * @see org.alfresco.cmis.search.CMISResultSet#getRow(int) + */ + public ResultSetRow getRow(int i) + { + return wrapped.getRow(getStart() + i); + } + + /* + * (non-Javadoc) + * + * @see org.alfresco.cmis.search.CMISResultSet#hasMore() + */ + public boolean hasMore() + { + + if (wrapped.getResultSetMetaData().getLimitedBy() != LimitBy.UNLIMITED) + { + return true; + } + else + { + if (wrapped.length() - getStart() > getLength()) + { + return true; + } + else + { + return false; + } + } + + } + + /* + * (non-Javadoc) + * + * @see org.alfresco.cmis.search.CMISResultSet#length() + */ + public int getLength() + { + + int max = searchParameters.getMaxItems(); + int skip = searchParameters.getSkipCount(); + if ((max >= 0) && (max < (wrapped.length() - skip))) + { + return searchParameters.getMaxItems(); + } + else + { + return wrapped.length() - skip; + } + + } + + /* + * (non-Javadoc) + * + * @see org.alfresco.cmis.search.CMISResultSet#start() + */ + public int getStart() + { + return searchParameters.getSkipCount(); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Iterable#iterator() + */ + public Iterator iterator() + { + return new PagingLuceneResultSetRowIteratorImpl(this); + } + + public ChildAssociationRef getChildAssocRef(int n) + { + NodeRef nodeRef = getNodeRef(n); + return nodeService.getPrimaryParent(nodeRef); + } + + public List getChildAssocRefs() + { + ArrayList cars = new ArrayList(length()); + for (ResultSetRow row : this) + { + cars.add(row.getChildAssocRef()); + } + return cars; + } + + public NodeRef getNodeRef(int n) + { + return wrapped.getNodeRef(getStart() + n); + } + + public List getNodeRefs() + { + ArrayList nodeRefs = new ArrayList(length()); + for (ResultSetRow row : this) + { + nodeRefs.add(row.getNodeRef()); + } + return nodeRefs; + } + + public ResultSetMetaData getResultSetMetaData() + { + return wrapped.getResultSetMetaData(); + } + + public float getScore(int n) + { + return wrapped.getScore(getStart() + n); + } + + public int length() + { + return getLength(); + } + + /** + * Get the underlying result Set + * @return the underlying result set + */ + public ResultSet getWrapped() + { + return wrapped; + } +} diff --git a/source/java/org/alfresco/repo/search/impl/lucene/PagingLuceneResultSetRowIteratorImpl.java b/source/java/org/alfresco/repo/search/impl/lucene/PagingLuceneResultSetRowIteratorImpl.java new file mode 100644 index 0000000000..fd9459f5ca --- /dev/null +++ b/source/java/org/alfresco/repo/search/impl/lucene/PagingLuceneResultSetRowIteratorImpl.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ +package org.alfresco.repo.search.impl.lucene; + +import java.util.ListIterator; + +import org.alfresco.service.cmr.search.ResultSetRow; + +/** + * @author andyh + */ +public class PagingLuceneResultSetRowIteratorImpl implements ListIterator +{ + /** + * The result set + */ + private PagingLuceneResultSet resultSet; + + /** + * The current position + */ + private int position = -1; + + /** + * The maximum position + */ + private int max; + + /** + * Create an iterator over the result set. Follows stadard ListIterator conventions + * + * @param resultSet + */ + public PagingLuceneResultSetRowIteratorImpl(PagingLuceneResultSet resultSet) + { + this.resultSet = resultSet; + this.max = resultSet.getLength(); + } + + public PagingLuceneResultSet getResultSet() + { + return resultSet; + } + + /* + * ListIterator implementation + */ + public boolean hasNext() + { + return position < (max - 1); + } + + public boolean allowsReverse() + { + return true; + } + + public boolean hasPrevious() + { + return position > 0; + } + + public ResultSetRow next() + { + return resultSet.getRow(moveToNextPosition()); + } + + protected int moveToNextPosition() + { + return ++position; + } + + public ResultSetRow previous() + { + return resultSet.getRow(moveToPreviousPosition()); + } + + protected int moveToPreviousPosition() + { + return --position; + } + + public int nextIndex() + { + return position + 1; + } + + public int previousIndex() + { + return position - 1; + } + + /* + * Mutation is not supported + */ + + public void remove() + { + throw new UnsupportedOperationException(); + } + + public void set(ResultSetRow o) + { + throw new UnsupportedOperationException(); + } + + public void add(ResultSetRow o) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/source/java/org/alfresco/repo/search/impl/querymodel/QueryOptions.java b/source/java/org/alfresco/repo/search/impl/querymodel/QueryOptions.java index 51a1a3148a..e64d6b0968 100644 --- a/source/java/org/alfresco/repo/search/impl/querymodel/QueryOptions.java +++ b/source/java/org/alfresco/repo/search/impl/querymodel/QueryOptions.java @@ -67,28 +67,38 @@ public class QueryOptions private boolean includeInTransactionData = true; + // By default uses the central config + private int maxPermissionChecks = -1; + + // By default uses the central config + private long maxPermissionCheckTimeMillis = -1; + /** - * Create a CMISQueryOptions instance with the default options other than the query and store ref. - * The query will be run using the locale returned by I18NUtil.getLocale() + * Create a CMISQueryOptions instance with the default options other than the query and store ref. The query will be + * run using the locale returned by I18NUtil.getLocale() * - * @param query - the query to run - * @param storeRef - the store against which to run the query + * @param query - + * the query to run + * @param storeRef - + * the store against which to run the query */ public QueryOptions(String query, StoreRef storeRef) { this(query, storeRef, I18NUtil.getLocale()); } - + /** * Create a CMISQueryOptions instance with the default options other than the query, store ref and locale. * - * @param query - the query to run - * @param storeRef - the store against which to run the query + * @param query - + * the query to run + * @param storeRef - + * the store against which to run the query */ public QueryOptions(String query, StoreRef storeRef, Locale locale) { this.query = query; - this.stores.add(storeRef); + this.stores.add(storeRef); this.locales.add(locale); } @@ -105,7 +115,8 @@ public class QueryOptions /** * Set the query string * - * @param query the query to set + * @param query + * the query to set */ public void setQuery(String query) { @@ -113,8 +124,8 @@ public class QueryOptions } /** - * Get the list of stores in which to run the query. - * Only one store is supported at the momentOnly one store is supported at the moment + * Get the list of stores in which to run the query. Only one store is supported at the momentOnly one store is + * supported at the moment * * @return the stores */ @@ -124,10 +135,10 @@ public class QueryOptions } /** - * Set the stores against which to run the query. - * Only one store is supported at the moment. + * Set the stores against which to run the query. Only one store is supported at the moment. * - * @param stores the stores to set + * @param stores + * the stores to set */ public void setStores(List stores) { @@ -135,8 +146,7 @@ public class QueryOptions } /** - * Get the max number of rows for the result set - * 0 or less is unlimited + * Get the max number of rows for the result set 0 or less is unlimited * * @return the maxItems */ @@ -146,10 +156,10 @@ public class QueryOptions } /** - * Set the max number of rows for the result set - * 0 or less is unlimited + * Set the max number of rows for the result set 0 or less is unlimited * - * @param maxItems the maxItems to set + * @param maxItems + * the maxItems to set */ public void setMaxItems(int maxItems) { @@ -169,7 +179,8 @@ public class QueryOptions /** * Set the skip count - the number of rows to skip at the start of the query. * - * @param skipCount the skipCount to set + * @param skipCount + * the skipCount to set */ public void setSkipCount(int skipCount) { @@ -189,7 +200,8 @@ public class QueryOptions /** * Set the default connective used when OR and AND are not specified for the FTS contains() function. * - * @param defaultFTSConnective the defaultFTSConnective to set + * @param defaultFTSConnective + * the defaultFTSConnective to set */ public void setDefaultFTSConnective(Connective defaultFTSConnective) { @@ -209,7 +221,8 @@ public class QueryOptions /** * As setDefaultFTSConnective() but for field groups * - * @param defaultFTSFieldConnective the defaultFTSFieldConnective to set + * @param defaultFTSFieldConnective + * the defaultFTSFieldConnective to set */ public void setDefaultFTSFieldConnective(Connective defaultFTSFieldConnective) { @@ -217,9 +230,7 @@ public class QueryOptions } /** - * Get the fetch size - * 0 - no prefetch - * -1 - prefetch all + * Get the fetch size 0 - no prefetch -1 - prefetch all * * @return the fetchSize */ @@ -229,11 +240,10 @@ public class QueryOptions } /** - * Set the fetch size - * 0 - no prefetch - * -1 - prefetch all + * Set the fetch size 0 - no prefetch -1 - prefetch all * - * @param fetchSize the fetchSize to set + * @param fetchSize + * the fetchSize to set */ public void setFetchSize(int fetchSize) { @@ -253,7 +263,8 @@ public class QueryOptions /** * sSet the list of locales to use for the query * - * @param locales the locales to set + * @param locales + * the locales to set */ public void setLocales(List locales) { @@ -261,7 +272,7 @@ public class QueryOptions } /** - * Get the mode for multi-lingual text analaysis + * Get the mode for multi-lingual text analaysis * * @return the mlAnalaysisMode */ @@ -273,7 +284,8 @@ public class QueryOptions /** * Set the mode for multi-lingual text analaysis * - * @param mlAnalaysisMode the mlAnalaysisMode to set + * @param mlAnalaysisMode + * the mlAnalaysisMode to set */ public void setMlAnalaysisMode(MLAnalysisMode mlAnalaysisMode) { @@ -293,7 +305,8 @@ public class QueryOptions /** * Set the query parameters * - * @param queryParameterDefinitions the queryParameterDefinitions to set + * @param queryParameterDefinitions + * the queryParameterDefinitions to set */ public void setQueryParameterDefinitions(List queryParameterDefinitions) { @@ -313,12 +326,46 @@ public class QueryOptions /** * Set to true if the search include any changes made in the current transaction. * - * @param includeInTransactionData the includeInTransactionData to set + * @param includeInTransactionData + * the includeInTransactionData to set */ public void setIncludeInTransactionData(boolean includeInTransactionData) { this.includeInTransactionData = includeInTransactionData; } - + /** + * @return the timeout in millis for permission checks + */ + public long getMaxPermissionCheckTimeMillis() + { + return maxPermissionCheckTimeMillis; + } + + /** + * @param maxPermissionCheckTimeMillis - + * the timeout in millis for permission checks + */ + public void setMaxPermissionCheckTimeMillis(long maxPermissionCheckTimeMillis) + { + this.maxPermissionCheckTimeMillis = maxPermissionCheckTimeMillis; + } + + /** + * @return the max number of permission checks to carry out + */ + public int getMaxPermissionChecks() + { + return maxPermissionChecks; + } + + /** + * @param maxPermissionChecks - + * the max number of permission checks to carry out + */ + public void setMaxPermissionChecks(int maxPermissionChecks) + { + this.maxPermissionChecks = maxPermissionChecks; + } + } diff --git a/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/LuceneQueryEngine.java b/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/LuceneQueryEngine.java index af8dbf9f37..1972c98236 100644 --- a/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/LuceneQueryEngine.java +++ b/source/java/org/alfresco/repo/search/impl/querymodel/impl/lucene/LuceneQueryEngine.java @@ -35,6 +35,7 @@ import org.alfresco.repo.search.impl.lucene.ClosingIndexSearcher; import org.alfresco.repo.search.impl.lucene.LuceneIndexerAndSearcher; import org.alfresco.repo.search.impl.lucene.LuceneResultSet; import org.alfresco.repo.search.impl.lucene.LuceneSearcher; +import org.alfresco.repo.search.impl.lucene.PagingLuceneResultSet; import org.alfresco.repo.search.impl.querymodel.FunctionEvaluationContext; import org.alfresco.repo.search.impl.querymodel.Query; import org.alfresco.repo.search.impl.querymodel.QueryEngine; @@ -142,10 +143,14 @@ public class LuceneQueryEngine implements QueryEngine SearchParameters searchParameters = new SearchParameters(); searchParameters.setBulkFetch(options.getFetchSize() > 0); searchParameters.setBulkFetchSize(options.getFetchSize()); - if (options.getMaxItems() > 0) + searchParameters.setSkipCount(options.getSkipCount()); + searchParameters.setMaxPermissionChecks(options.getMaxPermissionChecks()); + searchParameters.setMaxPermissionCheckTimeMillis(options.getMaxPermissionCheckTimeMillis()); + if (options.getMaxItems() >= 0) { searchParameters.setLimitBy(LimitBy.FINAL_SIZE); - searchParameters.setLimit(options.getMaxItems() + options.getSkipCount()); + searchParameters.setLimit(options.getMaxItems()); + searchParameters.setMaxItems(options.getMaxItems()); } else { @@ -183,8 +188,9 @@ public class LuceneQueryEngine implements QueryEngine } LuceneResultSet result = new LuceneResultSet(hits, searcher, nodeService, tenantService, searchParameters, indexAndSearcher); + ResultSet rs = new PagingLuceneResultSet(result, searchParameters, nodeService); Map, ResultSet> map = new HashMap, ResultSet>(1); - map.put(selectorGroup, result); + map.put(selectorGroup, rs); return new QueryEngineResults(map); } else diff --git a/source/java/org/alfresco/repo/security/permissions/impl/acegi/ACLEntryAfterInvocationProvider.java b/source/java/org/alfresco/repo/security/permissions/impl/acegi/ACLEntryAfterInvocationProvider.java index 24cd6ce50a..2df588cc55 100644 --- a/source/java/org/alfresco/repo/security/permissions/impl/acegi/ACLEntryAfterInvocationProvider.java +++ b/source/java/org/alfresco/repo/security/permissions/impl/acegi/ACLEntryAfterInvocationProvider.java @@ -42,6 +42,7 @@ import net.sf.acegisecurity.ConfigAttributeDefinition; import net.sf.acegisecurity.afterinvocation.AfterInvocationProvider; import org.alfresco.repo.search.SimpleResultSetMetaData; +import org.alfresco.repo.search.impl.lucene.PagingLuceneResultSet; import org.alfresco.repo.search.impl.querymodel.QueryEngineResults; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.permissions.impl.SimplePermissionReference; @@ -67,7 +68,6 @@ import org.springframework.beans.factory.InitializingBean; * Enforce permission after the method calll * * @author andyh - * */ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider, InitializingBean { @@ -78,9 +78,13 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider, private static final String AFTER_ACL_PARENT = "AFTER_ACL_PARENT"; private PermissionService permissionService; + private NamespacePrefixResolver nspr; + private NodeService nodeService; + private int maxPermissionChecks; + private long maxPermissionCheckTimeMillis; /** @@ -105,6 +109,7 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider, /** * Get the permission service. + * * @return - the permission service */ public PermissionService getPermissionService() @@ -114,6 +119,7 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider, /** * Get the namespace prefix resolver + * * @return the namespace prefix resolver */ public NamespacePrefixResolver getNamespacePrefixResolver() @@ -123,6 +129,7 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider, /** * Set the namespace prefix resolver + * * @param nspr */ public void setNamespacePrefixResolver(NamespacePrefixResolver nspr) @@ -130,8 +137,9 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider, this.nspr = nspr; } - /** + /** * Get the node service + * * @return the node service */ public NodeService getNodeService() @@ -141,6 +149,7 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider, /** * Set the node service + * * @param nodeService */ public void setNodeService(NodeService nodeService) @@ -148,26 +157,29 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider, this.nodeService = nodeService; } - /** + /** * Set the authentication service + * * @param authenticationService */ public void setAuthenticationService(AuthenticationService authenticationService) { log.warn("Bean property 'authenticationService' no longer required."); } - + /** * Set the max number of permission checks + * * @param maxPermissionChecks */ public void setMaxPermissionChecks(int maxPermissionChecks) { this.maxPermissionChecks = maxPermissionChecks; } - + /** * Set the max time for permission checks + * * @param maxPermissionCheckTimeMillis */ public void setMaxPermissionCheckTimeMillis(long maxPermissionCheckTimeMillis) @@ -191,8 +203,7 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider, } } - public Object decide(Authentication authentication, Object object, ConfigAttributeDefinition config, - Object returnedObject) throws AccessDeniedException + public Object decide(Authentication authentication, Object object, ConfigAttributeDefinition config, Object returnedObject) throws AccessDeniedException { if (log.isDebugEnabled()) { @@ -223,8 +234,7 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider, { log.debug("Store access"); } - return decide(authentication, object, config, nodeService.getRootNode((StoreRef) returnedObject)) - .getStoreRef(); + return decide(authentication, object, config, nodeService.getRootNode((StoreRef) returnedObject)).getStoreRef(); } else if (NodeRef.class.isAssignableFrom(returnedObject.getClass())) { @@ -254,6 +264,14 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider, } return decide(authentication, object, config, (ResultSet) returnedObject); } + else if (PagingLuceneResultSet.class.isAssignableFrom(returnedObject.getClass())) + { + if (log.isDebugEnabled()) + { + log.debug("Result Set access"); + } + return decide(authentication, object, config, (PagingLuceneResultSet) returnedObject); + } else if (QueryEngineResults.class.isAssignableFrom(returnedObject.getClass())) { if (log.isDebugEnabled()) @@ -308,12 +326,7 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider, } - - private NodeRef decide( - Authentication authentication, - Object object, - ConfigAttributeDefinition config, - NodeRef returnedObject) throws AccessDeniedException + private NodeRef decide(Authentication authentication, Object object, ConfigAttributeDefinition config, NodeRef returnedObject) throws AccessDeniedException { if (returnedObject == null) @@ -341,8 +354,7 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider, testNodeRef = nodeService.getPrimaryParent(returnedObject).getParentRef(); } - if ((testNodeRef != null) - && (permissionService.hasPermission(testNodeRef, cad.required.toString()) == AccessStatus.DENIED)) + if ((testNodeRef != null) && (permissionService.hasPermission(testNodeRef, cad.required.toString()) == AccessStatus.DENIED)) { throw new AccessDeniedException("Access Denied"); } @@ -352,11 +364,7 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider, return returnedObject; } - private FileInfo decide( - Authentication authentication, - Object object, - ConfigAttributeDefinition config, - FileInfo returnedObject) throws AccessDeniedException + private FileInfo decide(Authentication authentication, Object object, ConfigAttributeDefinition config, FileInfo returnedObject) throws AccessDeniedException { NodeRef nodeRef = returnedObject.getNodeRef(); @@ -384,8 +392,8 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider, return definitions; } - private ChildAssociationRef decide(Authentication authentication, Object object, ConfigAttributeDefinition config, - ChildAssociationRef returnedObject) throws AccessDeniedException + private ChildAssociationRef decide(Authentication authentication, Object object, ConfigAttributeDefinition config, ChildAssociationRef returnedObject) + throws AccessDeniedException { if (returnedObject == null) @@ -413,8 +421,7 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider, testNodeRef = ((ChildAssociationRef) returnedObject).getParentRef(); } - if ((testNodeRef != null) - && (permissionService.hasPermission(testNodeRef, cad.required.toString()) == AccessStatus.DENIED)) + if ((testNodeRef != null) && (permissionService.hasPermission(testNodeRef, cad.required.toString()) == AccessStatus.DENIED)) { throw new AccessDeniedException("Access Denied"); } @@ -424,71 +431,99 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider, return returnedObject; } - private ResultSet decide(Authentication authentication, Object object, ConfigAttributeDefinition config, - ResultSet returnedObject) throws AccessDeniedException + private ResultSet decide(Authentication authentication, Object object, ConfigAttributeDefinition config, PagingLuceneResultSet returnedObject) throws AccessDeniedException + + { + ResultSet raw = returnedObject.getWrapped(); + ResultSet filteredForPermissions = decide(authentication, object, config, raw); + PagingLuceneResultSet newPaging = new PagingLuceneResultSet(filteredForPermissions, returnedObject.getResultSetMetaData().getSearchParameters(), nodeService); + return newPaging; + } + + private ResultSet decide(Authentication authentication, Object object, ConfigAttributeDefinition config, ResultSet returnedObject) throws AccessDeniedException { if (returnedObject == null) { return null; } - + FilteringResultSet filteringResultSet = new FilteringResultSet(returnedObject); - List supportedDefinitions = extractSupportedDefinitions(config); Integer maxSize = null; - if(returnedObject.getResultSetMetaData().getSearchParameters().getLimitBy() == LimitBy.FINAL_SIZE) + if (returnedObject.getResultSetMetaData().getSearchParameters().getMaxItems() >= 0) + { + maxSize = new Integer(returnedObject.getResultSetMetaData().getSearchParameters().getMaxItems()); + } + if ((maxSize == null) && (returnedObject.getResultSetMetaData().getSearchParameters().getLimitBy() == LimitBy.FINAL_SIZE)) { maxSize = new Integer(returnedObject.getResultSetMetaData().getSearchParameters().getLimit()); } - + // Allow for skip + if ((maxSize != null) && (returnedObject.getResultSetMetaData().getSearchParameters().getSkipCount() >= 0)) + { + maxSize = new Integer(maxSize + returnedObject.getResultSetMetaData().getSearchParameters().getSkipCount()); + } + + int maxChecks = maxPermissionChecks; + if (returnedObject.getResultSetMetaData().getSearchParameters().getMaxPermissionChecks() >= 0) + { + maxChecks = returnedObject.getResultSetMetaData().getSearchParameters().getMaxPermissionChecks(); + } + + long maxCheckTime = maxPermissionCheckTimeMillis; + if (returnedObject.getResultSetMetaData().getSearchParameters().getMaxPermissionCheckTimeMillis() >= 0) + { + maxCheckTime = returnedObject.getResultSetMetaData().getSearchParameters().getMaxPermissionCheckTimeMillis(); + } + if (supportedDefinitions.size() == 0) { - if(maxSize == null) + if (maxSize == null) { - return returnedObject; + return returnedObject; } else if (returnedObject.length() > maxSize.intValue()) { - for(int i = 0; i < maxSize.intValue(); i++) + for (int i = 0; i < maxSize.intValue(); i++) { filteringResultSet.setIncluded(i, true); } - filteringResultSet.setResultSetMetaData(new SimpleResultSetMetaData(LimitBy.FINAL_SIZE, PermissionEvaluationMode.EAGER, returnedObject.getResultSetMetaData().getSearchParameters())); + filteringResultSet.setResultSetMetaData(new SimpleResultSetMetaData(LimitBy.FINAL_SIZE, PermissionEvaluationMode.EAGER, returnedObject.getResultSetMetaData() + .getSearchParameters())); } else { - for(int i = 0; i < maxSize.intValue(); i++) + for (int i = 0; i < maxSize.intValue(); i++) { filteringResultSet.setIncluded(i, true); } - filteringResultSet.setResultSetMetaData(new SimpleResultSetMetaData(LimitBy.UNLIMITED, PermissionEvaluationMode.EAGER, returnedObject.getResultSetMetaData().getSearchParameters())); + filteringResultSet.setResultSetMetaData(new SimpleResultSetMetaData(LimitBy.UNLIMITED, PermissionEvaluationMode.EAGER, returnedObject.getResultSetMetaData() + .getSearchParameters())); } } // record the start time long startTimeMillis = System.currentTimeMillis(); // set the default, unlimited resultset type - filteringResultSet.setResultSetMetaData(new SimpleResultSetMetaData(LimitBy.UNLIMITED, PermissionEvaluationMode.EAGER, returnedObject.getResultSetMetaData().getSearchParameters())); - + filteringResultSet.setResultSetMetaData(new SimpleResultSetMetaData(LimitBy.UNLIMITED, PermissionEvaluationMode.EAGER, returnedObject.getResultSetMetaData() + .getSearchParameters())); + for (int i = 0; i < returnedObject.length(); i++) { long currentTimeMillis = System.currentTimeMillis(); - if ( i >= maxPermissionChecks || (currentTimeMillis - startTimeMillis) > maxPermissionCheckTimeMillis) + if (i >= maxChecks || (currentTimeMillis - startTimeMillis) > maxCheckTime) { - filteringResultSet.setResultSetMetaData( - new SimpleResultSetMetaData( - LimitBy.NUMBER_OF_PERMISSION_EVALUATIONS, - PermissionEvaluationMode.EAGER, - returnedObject.getResultSetMetaData().getSearchParameters())); + filteringResultSet.setResultSetMetaData(new SimpleResultSetMetaData(LimitBy.NUMBER_OF_PERMISSION_EVALUATIONS, PermissionEvaluationMode.EAGER, returnedObject + .getResultSetMetaData().getSearchParameters())); break; } - + // All permission checks must pass filteringResultSet.setIncluded(i, true); - + for (ConfigAttributeDefintion cad : supportedDefinitions) { NodeRef testNodeRef = null; @@ -501,44 +536,50 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider, testNodeRef = returnedObject.getChildAssocRef(i).getParentRef(); } - if (filteringResultSet.getIncluded(i) - && (testNodeRef != null) - && (permissionService.hasPermission(testNodeRef, cad.required.toString()) == AccessStatus.DENIED)) + if (filteringResultSet.getIncluded(i) && (testNodeRef != null) && (permissionService.hasPermission(testNodeRef, cad.required.toString()) == AccessStatus.DENIED)) { filteringResultSet.setIncluded(i, false); } } - + // Bug out if we are limiting by size if ((maxSize != null) && (filteringResultSet.length() > maxSize.intValue())) { // Renove the last match to fix the correct size filteringResultSet.setIncluded(i, false); - filteringResultSet.setResultSetMetaData(new SimpleResultSetMetaData(LimitBy.FINAL_SIZE, PermissionEvaluationMode.EAGER, returnedObject.getResultSetMetaData().getSearchParameters())); + filteringResultSet.setResultSetMetaData(new SimpleResultSetMetaData(LimitBy.FINAL_SIZE, PermissionEvaluationMode.EAGER, returnedObject.getResultSetMetaData() + .getSearchParameters())); break; } } return filteringResultSet; } - private QueryEngineResults decide(Authentication authentication, Object object, ConfigAttributeDefinition config, - QueryEngineResults returnedObject) throws AccessDeniedException + private QueryEngineResults decide(Authentication authentication, Object object, ConfigAttributeDefinition config, QueryEngineResults returnedObject) + throws AccessDeniedException { Map, ResultSet> map = returnedObject.getResults(); Map, ResultSet> answer = new HashMap, ResultSet>(map.size(), 1.0f); - + for (Set group : map.keySet()) { ResultSet raw = map.get(group); - ResultSet permed = decide(authentication, object, config, raw); + ResultSet permed; + if (PagingLuceneResultSet.class.isAssignableFrom(raw.getClass())) + { + permed = decide(authentication, object, config, (PagingLuceneResultSet)raw); + } + else + { + permed = decide(authentication, object, config, raw); + } answer.put(group, permed); } return new QueryEngineResults(answer); } - - private Collection decide(Authentication authentication, Object object, ConfigAttributeDefinition config, - Collection returnedObject) throws AccessDeniedException + + private Collection decide(Authentication authentication, Object object, ConfigAttributeDefinition config, Collection returnedObject) throws AccessDeniedException { if (returnedObject == null) @@ -563,21 +604,21 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider, // record search start time long startTimeMillis = System.currentTimeMillis(); int count = 0; - + Iterator iterator = returnedObject.iterator(); while (iterator.hasNext()) { Object nextObject = iterator.next(); - + // if the maximum result size or time has been exceeded, then we have to remove only long currentTimeMillis = System.currentTimeMillis(); - if ( count >= maxPermissionChecks || (currentTimeMillis - startTimeMillis) > maxPermissionCheckTimeMillis) + if (count >= maxPermissionChecks || (currentTimeMillis - startTimeMillis) > maxPermissionCheckTimeMillis) { // just remove it iterator.remove(); continue; } - + boolean allowed = true; for (ConfigAttributeDefintion cad : supportedDefinitions) { @@ -603,8 +644,7 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider, } else { - throw new ACLEntryVoterException( - "The specified parameter is not a collection of NodeRefs, ChildAssociationRefs or FileInfos"); + throw new ACLEntryVoterException("The specified parameter is not a collection of NodeRefs, ChildAssociationRefs or FileInfos"); } } else if (cad.typeString.equals(AFTER_ACL_PARENT)) @@ -628,19 +668,16 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider, } else { - throw new ACLEntryVoterException( - "The specified parameter is not a collection of NodeRefs or ChildAssociationRefs"); + throw new ACLEntryVoterException("The specified parameter is not a collection of NodeRefs or ChildAssociationRefs"); } } - + if (log.isDebugEnabled()) { log.debug("\t" + cad.typeString + " test on " + testNodeRef + " from " + nextObject.getClass().getName()); } - - if (allowed - && (testNodeRef != null) - && (permissionService.hasPermission(testNodeRef, cad.required.toString()) == AccessStatus.DENIED)) + + if (allowed && (testNodeRef != null) && (permissionService.hasPermission(testNodeRef, cad.required.toString()) == AccessStatus.DENIED)) { allowed = false; } @@ -658,8 +695,7 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider, return returnedObject; } - private Object[] decide(Authentication authentication, Object object, ConfigAttributeDefinition config, - Object[] returnedObject) throws AccessDeniedException + private Object[] decide(Authentication authentication, Object object, ConfigAttributeDefinition config, Object[] returnedObject) throws AccessDeniedException { BitSet incudedSet = new BitSet(returnedObject.length); @@ -736,9 +772,7 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider, log.debug("\t" + cad.typeString + " test on " + testNodeRef + " from " + current.getClass().getName()); } - if (incudedSet.get(i) - && (testNodeRef != null) - && (permissionService.hasPermission(testNodeRef, cad.required.toString()) == AccessStatus.DENIED)) + if (incudedSet.get(i) && (testNodeRef != null) && (permissionService.hasPermission(testNodeRef, cad.required.toString()) == AccessStatus.DENIED)) { incudedSet.set(i, false); } @@ -763,9 +797,7 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider, public boolean supports(ConfigAttribute attribute) { - if ((attribute.getAttribute() != null) - && (attribute.getAttribute().startsWith(AFTER_ACL_NODE) || attribute.getAttribute().startsWith( - AFTER_ACL_PARENT))) + if ((attribute.getAttribute() != null) && (attribute.getAttribute().startsWith(AFTER_ACL_NODE) || attribute.getAttribute().startsWith(AFTER_ACL_PARENT))) { return true; } diff --git a/source/java/org/alfresco/service/cmr/search/SearchParameters.java b/source/java/org/alfresco/service/cmr/search/SearchParameters.java index f61b8f5d90..d12f70c5b2 100644 --- a/source/java/org/alfresco/service/cmr/search/SearchParameters.java +++ b/source/java/org/alfresco/service/cmr/search/SearchParameters.java @@ -85,7 +85,7 @@ public class SearchParameters /** * OR */ - OR, + OR, /** * AND */ @@ -100,7 +100,7 @@ public class SearchParameters */ public static final Operator OR = Operator.OR; - /** + /** * AND */ public static final Operator AND = Operator.AND; @@ -150,6 +150,12 @@ public class SearchParameters private String namespace = NamespaceService.CONTENT_MODEL_1_0_URI; + // By default uses the central config + private int maxPermissionChecks = -1; + + // By default uses the central config + private long maxPermissionCheckTimeMillis = -1; + /** * Default constructor */ @@ -160,7 +166,8 @@ public class SearchParameters /** * Get the search language - * @return - string id of search language + * + * @return - string id of search language */ public String getLanguage() { @@ -214,7 +221,6 @@ public class SearchParameters stores.add(store); } - /** * Add parameter definitions for the query - used to parameterise the query string * @@ -319,7 +325,7 @@ public class SearchParameters /** * Get the default operator for query elements when they are not explicit in the query. * - * @return the default operator + * @return the default operator */ public Operator getDefaultOperator() { @@ -329,7 +335,7 @@ public class SearchParameters /** * Get how the result set should be limited * - * @return how the result set will be limited + * @return how the result set will be or was limited */ public LimitBy getLimitBy() { @@ -431,7 +437,8 @@ public class SearchParameters /** * Add a field for TEXT expansion * - * @param attribute - field/attribute in the index + * @param attribute - + * field/attribute in the index */ public void addTextAttribute(String attribute) { @@ -451,7 +458,8 @@ public class SearchParameters /** * Add a field for ALL expansion * - * @param attribute - field/attribute in the index + * @param attribute - + * field/attribute in the index */ public void addAllAttribute(String attribute) { @@ -594,6 +602,7 @@ public class SearchParameters /** * Get the default namespace. + * * @return the default namspace uri or prefix. */ public String getNamespace() @@ -603,16 +612,18 @@ public class SearchParameters /** * Set the default namespace - * @param namespace - the uri or prefix for the default namespace. + * + * @param namespace - + * the uri or prefix for the default namespace. */ public void setNamespace(String namespace) { this.namespace = namespace; } - /** * Get the query templates + * * @return - the query templates */ public Map getQueryTemplates() @@ -621,17 +632,42 @@ public class SearchParameters } /** - * Add/replace a query template - * Not all languages support query templates - * @param name - * @param template + * Add/replace a query template Not all languages support query templates + * + * @param name + * @param template * @return any removed template or null */ public String addQueryTemplate(String name, String template) { return queryTemplates.put(name, template); } - + + public long getMaxPermissionCheckTimeMillis() + { + return maxPermissionCheckTimeMillis; + } + + public void setMaxPermissionCheckTimeMillis(long maxPermissionCheckTimeMillis) + { + this.maxPermissionCheckTimeMillis = maxPermissionCheckTimeMillis; + } + + public int getMaxPermissionChecks() + { + return maxPermissionChecks; + } + + public void setMaxPermissionChecks(int maxPermissionChecks) + { + this.maxPermissionChecks = maxPermissionChecks; + } + + public int getBulkFetchSize() + { + return bulkFetchSize; + } + /** * A helper class for sort definition. Encapsulated using the lucene sortType, field name and a flag for * ascending/descending. @@ -643,19 +679,19 @@ public class SearchParameters /** * What is used for the sort + * * @author andyh - * */ public enum SortType { /** * A Field */ - FIELD, + FIELD, /** * Doc number */ - DOCUMENT, + DOCUMENT, /** * Score */ @@ -677,6 +713,7 @@ public class SearchParameters /** * Is ascending + * * @return true if ascending */ public boolean isAscending() @@ -686,6 +723,7 @@ public class SearchParameters /** * Field + * * @return - the field */ public String getField() @@ -695,6 +733,7 @@ public class SearchParameters /** * What is used for the sort + * * @return sort type */ public SortType getSortType() @@ -704,6 +743,4 @@ public class SearchParameters } - - }