diff --git a/source/java/org/alfresco/repo/search/impl/lucene/LuceneCategoryServiceImpl.java b/source/java/org/alfresco/repo/search/impl/lucene/LuceneCategoryServiceImpl.java index f3fe54d7c4..052dbdcb2a 100644 --- a/source/java/org/alfresco/repo/search/impl/lucene/LuceneCategoryServiceImpl.java +++ b/source/java/org/alfresco/repo/search/impl/lucene/LuceneCategoryServiceImpl.java @@ -47,6 +47,7 @@ import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.Path; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.search.CategoryService; +import org.alfresco.service.cmr.search.LimitBy; import org.alfresco.service.cmr.search.ResultSet; import org.alfresco.service.cmr.search.ResultSetRow; import org.alfresco.service.cmr.search.SearchParameters; @@ -147,10 +148,15 @@ public class LuceneCategoryServiceImpl implements CategoryService public Collection getChildren(NodeRef categoryRef, Mode mode, Depth depth) { - return getChildren(categoryRef, mode, depth, false); + return getChildren(categoryRef, mode, depth, false, null); + } + + public Collection getChildren(NodeRef categoryRef, Mode mode, Depth depth, String filter) + { + return getChildren(categoryRef, mode, depth, false, filter); } - private Collection getChildren(NodeRef categoryRef, Mode mode, Depth depth, boolean sortByName) + private Collection getChildren(NodeRef categoryRef, Mode mode, Depth depth, boolean sortByName, String filter) { if (categoryRef == null) { @@ -195,18 +201,26 @@ public class LuceneCategoryServiceImpl implements CategoryService luceneQuery.append("+TYPE:\"" + ContentModel.TYPE_CATEGORY.toString() + "\""); break; } + if (filter != null) + { + luceneQuery.append(" " + "+@cm\\:name:\"*" + filter + "*\""); + } // Get a searcher that will include Categories added in this transaction SearchService searcher = indexerAndSearcher.getSearcher(categoryRef.getStoreRef(), true); // Perform the search SearchParameters searchParameters = new SearchParameters(); - searchParameters.setQuery(luceneQuery.toString()); + resultSet = searcher.query(categoryRef.getStoreRef(), "lucene", luceneQuery.toString(), null); searchParameters.setLanguage("lucene"); if(sortByName) { searchParameters.addSort("@" + ContentModel.PROP_NAME, true); } + searchParameters.setQuery(luceneQuery.toString()); + searchParameters.setLimit(-1); + searchParameters.setMaxItems(Integer.MAX_VALUE); + searchParameters.setLimitBy(LimitBy.UNLIMITED); searchParameters.addStore(categoryRef.getStoreRef()); resultSet = searcher.query(searchParameters); @@ -368,7 +382,7 @@ public class LuceneCategoryServiceImpl implements CategoryService OUTER: for(NodeRef nodeRef : nodeRefs) { - Collection children = getChildren(nodeRef, Mode.SUB_CATEGORIES, Depth.IMMEDIATE, sortByName); + Collection children = getChildren(nodeRef, Mode.SUB_CATEGORIES, Depth.IMMEDIATE, sortByName, null); for(ChildAssociationRef child : children) { count++; @@ -418,12 +432,17 @@ public class LuceneCategoryServiceImpl implements CategoryService } public Collection getRootCategories(StoreRef storeRef, QName aspectName) + { + return getRootCategories(storeRef, aspectName, null); + } + + public Collection getRootCategories(StoreRef storeRef, QName aspectName, String filter) { Collection assocs = new LinkedList(); Set nodeRefs = getClassificationNodes(storeRef, aspectName); for (NodeRef nodeRef : nodeRefs) { - assocs.addAll(getChildren(nodeRef, Mode.SUB_CATEGORIES, Depth.IMMEDIATE)); + assocs.addAll(getChildren(nodeRef, Mode.SUB_CATEGORIES, Depth.IMMEDIATE, false, filter)); } return assocs; } diff --git a/source/java/org/alfresco/repo/tagging/TaggingServiceImpl.java b/source/java/org/alfresco/repo/tagging/TaggingServiceImpl.java index 891cce8be0..43d2cd9bc5 100644 --- a/source/java/org/alfresco/repo/tagging/TaggingServiceImpl.java +++ b/source/java/org/alfresco/repo/tagging/TaggingServiceImpl.java @@ -518,6 +518,36 @@ public class TaggingServiceImpl implements TaggingService, } return result; } + + public Pair, Integer> getPagedTags(StoreRef storeRef, int fromTag, int pageSize) + { + ParameterCheck.mandatory("storeRef", storeRef); + ParameterCheck.mandatory("fromTag", fromTag); + ParameterCheck.mandatory("pageSize", pageSize); + + Collection rootCategories = this.categoryService.getRootCategories(storeRef, ContentModel.ASPECT_TAGGABLE); + + final int totalCount = rootCategories.size(); + final int startIndex = Math.max(fromTag, 0); + final int endIndex = Math.min(fromTag + pageSize, totalCount); + List result = new ArrayList(pageSize); + int index = 0; + // paging for not sorted tag names + for (ChildAssociationRef rootCategory : rootCategories) + { + if (startIndex > index++) + { + continue; + } + String name = (String)this.nodeService.getProperty(rootCategory.getChildRef(), ContentModel.PROP_NAME); + result.add(name); + if (index == endIndex) + { + break; + } + } + return new Pair, Integer> (result, totalCount); + } /** * @see org.alfresco.service.cmr.tagging.TaggingService#getTags(org.alfresco.service.cmr.repository.StoreRef, java.lang.String) @@ -547,7 +577,44 @@ public class TaggingServiceImpl implements TaggingService, return result; } - + + public Pair, Integer> getPagedTags(StoreRef storeRef, String filter, int fromTag, int pageSize) + { + ParameterCheck.mandatory("storeRef", storeRef); + ParameterCheck.mandatory("fromTag", fromTag); + ParameterCheck.mandatory("pageSize", pageSize); + + if (filter == null || filter.length() == 0) + { + return getPagedTags(storeRef, fromTag, pageSize); + } + else + { + Collection rootCategories = this.categoryService.getRootCategories(storeRef, ContentModel.ASPECT_TAGGABLE, filter); + + final int totalCount = rootCategories.size(); + final int startIndex = Math.max(fromTag, 0); + final int endIndex = Math.min(fromTag + pageSize, totalCount); + List result = new ArrayList(pageSize); + int index = 0; + // paging for not sorted tag names + for (ChildAssociationRef rootCategory : rootCategories) + { + if (startIndex > index++) + { + continue; + } + String name = (String)this.nodeService.getProperty(rootCategory.getChildRef(), ContentModel.PROP_NAME); + result.add(name); + if (index == endIndex) + { + break; + } + } + return new Pair, Integer> (result, totalCount); + } + } + /** * @see org.alfresco.service.cmr.tagging.TaggingService#hasTag(org.alfresco.service.cmr.repository.NodeRef, java.lang.String) */ @@ -1423,5 +1490,6 @@ public class TaggingServiceImpl implements TaggingService, */ public void flush() { - } + } + } diff --git a/source/java/org/alfresco/repo/tagging/script/PagedTagsWrapper.java b/source/java/org/alfresco/repo/tagging/script/PagedTagsWrapper.java new file mode 100644 index 0000000000..f4530dd43f --- /dev/null +++ b/source/java/org/alfresco/repo/tagging/script/PagedTagsWrapper.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2005-2013 Alfresco Software Limited. + * + * This file is part of Alfresco + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ +package org.alfresco.repo.tagging.script; + +/** + * Stores total tags count together with tags to be sent to UI + * + * @author Viachaslau Tsikhanovich + * + */ +public class PagedTagsWrapper +{ + + private String[] tagNames; + + private String total; + + public PagedTagsWrapper(String[] tagNames, int total) + { + super(); + this.setTagNames(tagNames); + this.setTotal(total); + } + + public String[] getTagNames() + { + return tagNames; + } + + public void setTagNames(String[] tagNames) + { + this.tagNames = tagNames; + } + + public String getTotal() + { + return total; + } + + public void setTotal(int total) + { + this.total = String.valueOf(total); + } + +} diff --git a/source/java/org/alfresco/repo/tagging/script/ScriptTaggingService.java b/source/java/org/alfresco/repo/tagging/script/ScriptTaggingService.java index 65c01ba46c..b07cc15d2b 100644 --- a/source/java/org/alfresco/repo/tagging/script/ScriptTaggingService.java +++ b/source/java/org/alfresco/repo/tagging/script/ScriptTaggingService.java @@ -25,6 +25,7 @@ import org.alfresco.repo.jscript.ScriptNode; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.util.Pair; /** @@ -60,6 +61,22 @@ public class ScriptTaggingService extends BaseScopableProcessorExtension return (String[])result.toArray(new String[result.size()]); } + /** + * Get page of tags with totalRecords info + * + * @param store + * @param fromTag + * @param pageSize + * @return + */ + public PagedTagsWrapper getPagedTags(String store, int fromTag, int pageSize) + { + StoreRef storeRef = new StoreRef(store); + Pair, Integer> page = this.serviceRegistry.getTaggingService().getPagedTags(storeRef, fromTag, pageSize); + List result = page.getFirst(); + return new PagedTagsWrapper((String[])result.toArray(new String[result.size()]), page.getSecond()); + } + /** * Get all the tags available in a store based on a text filter * @@ -74,6 +91,14 @@ public class ScriptTaggingService extends BaseScopableProcessorExtension return (String[])result.toArray(new String[result.size()]); } + public PagedTagsWrapper getPagedTags(String store, String filter, int fromTag, int pageSize) + { + StoreRef storeRef = new StoreRef(store); + Pair, Integer> page = this.serviceRegistry.getTaggingService().getPagedTags(storeRef, filter, fromTag, pageSize); + List result = page.getFirst(); + return new PagedTagsWrapper((String[])result.toArray(new String[result.size()]), page.getSecond()); + } + /** * Get a tag by name if available in a store * diff --git a/source/java/org/alfresco/service/cmr/search/CategoryService.java b/source/java/org/alfresco/service/cmr/search/CategoryService.java index dad856d028..39124104f2 100644 --- a/source/java/org/alfresco/service/cmr/search/CategoryService.java +++ b/source/java/org/alfresco/service/cmr/search/CategoryService.java @@ -114,6 +114,17 @@ public interface CategoryService @Auditable(parameters = {"storeRef", "aspectName", "pagingRequest", "sortByName"}) PagingResults getRootCategories(StoreRef storeRef, QName aspectName, PagingRequest pagingRequest, boolean sortByName); + /** + * Get the root categories for an aspect/classification with names that start with filter + * + * @param storeRef + * @param aspectName + * @param filter + * @return + */ + @Auditable(parameters = {"storeRef", "aspectName"}) + public Collection getRootCategories(StoreRef storeRef, QName aspectName, String filter); + /** * Looks up a category by name under its immediate parent. Index-independent so can be used for cluster-safe * existence checks. diff --git a/source/java/org/alfresco/service/cmr/tagging/TaggingService.java b/source/java/org/alfresco/service/cmr/tagging/TaggingService.java index af65954143..df05cfc80a 100644 --- a/source/java/org/alfresco/service/cmr/tagging/TaggingService.java +++ b/source/java/org/alfresco/service/cmr/tagging/TaggingService.java @@ -275,6 +275,28 @@ public interface TaggingService */ @NotAuditable List findTaggedNodes(StoreRef storeRef, String tag, NodeRef nodeRef); + + /** + * Get page of the tags currently available + * + * @param storeRef node reference + * @param fromTag offset + * @param pageSize page size + * @return Pair, Integer> pair of tag names and total count + */ + @NotAuditable + Pair, Integer> getPagedTags(StoreRef storeRef, int fromTag, int pageSize); + + /** + * + * @param storeRef node reference + * @param filter tag filter + * @param fromTag page offset + * @param pageSize page size + * @return Pair, Integer> pair of tag names and total count + */ + @NotAuditable + Pair, Integer> getPagedTags(StoreRef storeRef, String filter, int fromTag, int pageSize); } diff --git a/source/test-java/org/alfresco/repo/search/impl/lucene/ADMLuceneCategoryTest.java b/source/test-java/org/alfresco/repo/search/impl/lucene/ADMLuceneCategoryTest.java index f01ec54499..debf046106 100644 --- a/source/test-java/org/alfresco/repo/search/impl/lucene/ADMLuceneCategoryTest.java +++ b/source/test-java/org/alfresco/repo/search/impl/lucene/ADMLuceneCategoryTest.java @@ -740,6 +740,18 @@ public class ADMLuceneCategoryTest extends TestCase tx = transactionService.getUserTransaction(); tx.begin(); assertEquals(3, categoryService.getRootCategories(rootNodeRef.getStoreRef(), QName.createQName(TEST_NAMESPACE, "assetClass")).size()); + Collection fruitCategories = categoryService.getRootCategories(rootNodeRef.getStoreRef(), QName.createQName(TEST_NAMESPACE, "assetClass"), "Fruit"); + assertEquals(1, fruitCategories.size()); + assertTrue(fruitCategories.iterator().next().getQName().toString().contains("Fruit")); + fruitCategories = categoryService.getRootCategories(rootNodeRef.getStoreRef(), QName.createQName(TEST_NAMESPACE, "assetClass"), "Fru"); + assertEquals(1, fruitCategories.size()); + assertTrue(fruitCategories.iterator().next().getQName().toString().contains("Fruit")); + fruitCategories = categoryService.getRootCategories(rootNodeRef.getStoreRef(), QName.createQName(TEST_NAMESPACE, "assetClass"), "rui"); + assertEquals(1, fruitCategories.size()); + assertTrue(fruitCategories.iterator().next().getQName().toString().contains("Fruit")); + fruitCategories = categoryService.getRootCategories(rootNodeRef.getStoreRef(), QName.createQName(TEST_NAMESPACE, "assetClass"), "uit"); + assertEquals(1, fruitCategories.size()); + assertTrue(fruitCategories.iterator().next().getQName().toString().contains("Fruit")); assertEquals(3, categoryService.getCategories(rootNodeRef.getStoreRef(), QName.createQName(TEST_NAMESPACE, "assetClass"), CategoryService.Depth.IMMEDIATE).size()); assertEquals(4, categoryService.getCategories(rootNodeRef.getStoreRef(), QName.createQName(TEST_NAMESPACE, "assetClass"), CategoryService.Depth.ANY).size()); diff --git a/source/test-java/org/alfresco/repo/tagging/TaggingServiceImplTest.java b/source/test-java/org/alfresco/repo/tagging/TaggingServiceImplTest.java index 0fae9e487e..4f1b41f6bd 100644 --- a/source/test-java/org/alfresco/repo/tagging/TaggingServiceImplTest.java +++ b/source/test-java/org/alfresco/repo/tagging/TaggingServiceImplTest.java @@ -66,6 +66,7 @@ import org.alfresco.service.transaction.TransactionService; import org.alfresco.test_category.OwnJVMTestsCategory; import org.alfresco.util.ApplicationContextHelper; import org.alfresco.util.GUID; +import org.alfresco.util.Pair; import org.alfresco.util.PropertyMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -337,6 +338,15 @@ public class TaggingServiceImplTest extends TestCase assertTrue(tags.contains(TAG_1)); assertTrue(tags.contains(LOWER_TAG)); + // Get Paged tags with filter + Pair, Integer> pagedTags = taggingService.getPagedTags(TaggingServiceImplTest.storeRef, "one", 0 ,10); + assertNotNull(pagedTags); + List tagPage = pagedTags.getFirst(); + int allFilteredTagsCount = pagedTags.getSecond(); + assertEquals(1, allFilteredTagsCount); + assertEquals(1, tagPage.size()); + assertTrue(tagPage.get(0).contains("one")); + // Check isTag method assertFalse(taggingService.isTag(TaggingServiceImplTest.storeRef, TAG_2)); assertTrue(taggingService.isTag(TaggingServiceImplTest.storeRef, TAG_1));