diff --git a/source/java/org/alfresco/repo/site/SiteServiceImpl.java b/source/java/org/alfresco/repo/site/SiteServiceImpl.java index 5b63a64ef2..dd983872fb 100644 --- a/source/java/org/alfresco/repo/site/SiteServiceImpl.java +++ b/source/java/org/alfresco/repo/site/SiteServiceImpl.java @@ -58,7 +58,6 @@ import org.alfresco.repo.node.getchildren.GetChildrenCannedQueryFactory; import org.alfresco.repo.policy.BehaviourFilter; import org.alfresco.repo.policy.JavaBehaviour; import org.alfresco.repo.policy.PolicyComponent; -import org.alfresco.repo.search.impl.lucene.AbstractLuceneQueryParser; import org.alfresco.repo.security.authentication.AuthenticationContext; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; @@ -112,6 +111,7 @@ import org.json.JSONObject; import org.springframework.context.ApplicationEvent; import org.springframework.extensions.surf.util.AbstractLifecycleBean; import org.springframework.extensions.surf.util.ParameterCheck; +import org.springframework.util.StringUtils; /** * Site Service Implementation. Also bootstraps the site AVM and DM stores. @@ -810,6 +810,81 @@ public class SiteServiceImpl extends AbstractLifecycleBean implements SiteServic return siteHomeRef; } + /* + * (non-Javadoc) + * @see org.alfresco.service.cmr.site.SiteService#findSites(java.lang.String, int) + */ + @Override + public List findSites(String filter, int size) + { + List result; + + NodeRef siteRoot = getSiteRoot(); + if (siteRoot == null) + { + result = Collections.emptyList(); + } + else + { + // get the sites that match the specified names + StringBuilder query = new StringBuilder(128); + query.append("+TYPE:\"").append(SiteModel.TYPE_SITE).append('"'); + + final boolean filterIsPresent = filter != null && filter.length() > 0; + + if (filterIsPresent) + { + query.append(" AND ("); + String escNameFilter = SearchLanguageConversion.escapeLuceneQuery(filter.replace('"', ' ')); + String[] tokenizedFilter = SearchLanguageConversion.tokenizeString(escNameFilter); + query.append(" cm:name:\"" + StringUtils.trimAllWhitespace(escNameFilter) + "*\"") + .append(" OR ") + .append(" cm:title: ("); + for (String token: tokenizedFilter) + { + query.append("\""+token+"*\" "); + } +// for( int i = 0; i < tokenizedFilter.length; i++) +// { +// if (i!=0) //Not first element +// { +// query.append(" AND |"); +// } +// query.append(tokenizedFilter[i]+"*"); +// } + query.append(")"); + + query.append(" OR cm:description:\"" + escNameFilter + "\""); + query.append(")"); + } + + SearchParameters sp = new SearchParameters(); + sp.addStore(siteRoot.getStoreRef()); + sp.setLanguage(SearchService.LANGUAGE_FTS_ALFRESCO); + sp.setQuery(query.toString()); + if (size > 0) + { + sp.setLimit(size); + sp.setLimitBy(LimitBy.FINAL_SIZE); + } + + ResultSet results = this.searchService.query(sp); + try + { + result = new ArrayList(results.length()); + for (NodeRef site : results.getNodeRefs()) + { + result.add(createSiteInfo(site)); + } + } + finally + { + results.close(); + } + } + + return result; + } /* * (non-Javadoc) * @see org.alfresco.service.cmr.site.SiteService#findSites(java.lang.String, java.lang.String, int) diff --git a/source/java/org/alfresco/repo/site/script/ScriptSiteService.java b/source/java/org/alfresco/repo/site/script/ScriptSiteService.java index 95e9d2ec21..cc9760e88a 100644 --- a/source/java/org/alfresco/repo/site/script/ScriptSiteService.java +++ b/source/java/org/alfresco/repo/site/script/ScriptSiteService.java @@ -261,7 +261,25 @@ public class ScriptSiteService extends BaseScopableProcessorExtension List siteInfos = this.siteService.findSites(filter, sitePresetFilter, size); return makeSitesArray(siteInfos); } - + + /** + * Find (search) the sites available in the repository. The returned list can optionally be filtered by name + *

+ * + * @param filter inclusion filter for returned sites. Only sites whose cm:name OR cm:title + * OR cm:description CONTAIN the filter string will be returned. + * @param size max results size crop if >0 + * + * @return Site[] a list of the site filtered as appropriate + * + * @see SiteService#findSites(String, int) for a description of the limitations of this method. + * @since 5.0 + */ + public Site[] findSites(String filter, int size) + { + List siteInfos = this.siteService.findSites(filter, size); + return makeSitesArray(siteInfos); + } /** * Converts the given List of SiteInfo objects to a JavaScript friendly array * of Site objects. diff --git a/source/java/org/alfresco/service/cmr/site/SiteService.java b/source/java/org/alfresco/service/cmr/site/SiteService.java index 598f5a0d60..c3437d151c 100644 --- a/source/java/org/alfresco/service/cmr/site/SiteService.java +++ b/source/java/org/alfresco/service/cmr/site/SiteService.java @@ -145,6 +145,23 @@ public interface SiteService @NotAuditable List findSites(String filter, String sitePresetFilter, int size); + /** + * This method will find all {@link SiteInfo sites} available to the currently authenticated user based on + * the specified site filter and result set size. + * The filter parameter will match any sites whose {@link ContentModel#PROP_NAME cm:name}, {@link ContentModel#PROP_TITLE cm:title} + * or {@link ContentModel#PROP_DESCRIPTION cm:description} contain the specified string (ignoring case). + *

+ * Note that this method uses Alfresco Full Text Search to retrieve results + * and depending on server Lucene, SOLR configuration may only offer eventually consistent results. + * + * @param filter Any supplied filter will be wrapped in asterisks (e.g. 'foo*') and used to match the sites' cm:name, cm:title or cm:description. + * @param size this parameter specifies a maximum result set size. + * @return Site objects for all matching sites up to the maximum result size. + * + * @since 5.0 + */ + @NotAuditable + List findSites(String filter, int size); /** * List the available sites. This list can optionally be filtered by site name/title/description and/or site preset. *

diff --git a/source/test-java/org/alfresco/repo/site/SiteServiceImplTest.java b/source/test-java/org/alfresco/repo/site/SiteServiceImplTest.java index ea56368729..564293cfbe 100644 --- a/source/test-java/org/alfresco/repo/site/SiteServiceImplTest.java +++ b/source/test-java/org/alfresco/repo/site/SiteServiceImplTest.java @@ -69,7 +69,6 @@ import org.alfresco.service.cmr.tagging.TaggingService; import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.QName; import org.alfresco.test_category.BaseSpringTestsCategory; -import org.alfresco.test_category.OwnJVMTestsCategory; import org.alfresco.util.BaseAlfrescoSpringTest; import org.alfresco.util.GUID; import org.alfresco.util.PropertyMap; @@ -702,6 +701,135 @@ public class SiteServiceImplTest extends BaseAlfrescoSpringTest assertEquals("Matched wrong number of sites using '?'", 2, sites.size()); } + /** + * This test method ensures that searches with wildcards work as they should + */ + public void testfindSitesForLiveSearchWithWildcardTitles() throws Exception + { + // How many sites are there already in the repo? + List preexistingSites = this.siteService.findSites(null, 0); + final int preexistingSitesCount = preexistingSites.size(); + + // Create some test sites + // + // Note that the shortName can't contain an asterisk but the title can. + this.siteService.createSite(TEST_SITE_PRESET, "siteLiveA", "getafix", TEST_DESCRIPTION, SiteVisibility.PUBLIC); + this.siteService.createSite(TEST_SITE_PRESET, "siteLiveB", "getafix1vitalstatistix", TEST_DESCRIPTION, SiteVisibility.PUBLIC); + this.siteService.createSite(TEST_SITE_PRESET, "siteLiveC", "Armorican Gaul France", TEST_DESCRIPTION, SiteVisibility.PUBLIC); + + //ACE-1428 + this.siteService.createSite(TEST_SITE_PRESET, "siteLiveD", "n3w s1t3 creat3ed 88", TEST_DESCRIPTION, SiteVisibility.PUBLIC); + this.siteService.createSite(TEST_SITE_PRESET, "siteLiveE", "n3w s1t3 creat3ed 99", TEST_DESCRIPTION, SiteVisibility.PUBLIC); + + //More scenarios + this.siteService.createSite(TEST_SITE_PRESET, "siteLiveF", "super exciting product", TEST_DESCRIPTION, SiteVisibility.PUBLIC); + this.siteService.createSite(TEST_SITE_PRESET, "siteLiveG", "super exciting launch", TEST_DESCRIPTION, SiteVisibility.PUBLIC); + this.siteService.createSite(TEST_SITE_PRESET, "siteLiveH", "amazing sales 54", TEST_DESCRIPTION, SiteVisibility.PUBLIC); + this.siteService.createSite(TEST_SITE_PRESET, "siteLiveI", "wonderfulsupport32", TEST_DESCRIPTION, SiteVisibility.PUBLIC); + this.siteService.createSite(TEST_SITE_PRESET, "siteLiveJ", "great89service", TEST_DESCRIPTION, SiteVisibility.PUBLIC); + this.siteService.createSite(TEST_SITE_PRESET, "siteLiveK", "my top draw", TEST_DESCRIPTION, SiteVisibility.PUBLIC); + + // Get sites by matching title + List sites = this.siteService.findSites("getafix", 0); + assertNotNull(sites); + // As the name & description do not contain "asterix", this will become a search for sites whose titles match "asterix" + assertEquals("Matched wrong number of sites with title equal to 'getafix'", 2, sites.size()); + + // This means 'find all' + sites = this.siteService.findSites("*", 0); + assertNotNull(sites); + assertEquals("Matched wrong number of sites using '*'", preexistingSitesCount + 11, sites.size()); + + sites = this.siteService.findSites("ge?afix", 0); + assertNotNull(sites); + assertEquals("Matched wrong number of sites using '?'", 2, sites.size()); + + sites = this.siteService.findSites("Armorican", 0); + assertNotNull(sites); + assertEquals("Matched wrong number of sites for tokenized search", 1, sites.size()); + + sites = this.siteService.findSites("Gaul", 0); + assertNotNull(sites); + assertEquals("Matched wrong number of sites for tokenized search", 1, sites.size()); + + sites = this.siteService.findSites("France", 0); + assertNotNull(sites); + assertEquals("Matched wrong number of sites for tokenized search", 1, sites.size()); + + sites = this.siteService.findSites("Armorican Gaul", 0); + assertNotNull(sites); + assertEquals("Matched wrong number of sites for tokenized search", 1, sites.size()); + + sites = this.siteService.findSites("Armori", 0); + assertNotNull(sites); + assertEquals("Matched wrong number of sites for tokenized search", 1, sites.size()); + + sites = this.siteService.findSites("Fran", 0); + assertNotNull(sites); + assertEquals("Matched wrong number of sites for tokenized search", 1, sites.size()); + +// sites = this.siteService.findSites("n3w s1t3 88", 0); +// assertNotNull(sites); +// assertEquals("Matched wrong number of sites for tokenized search", 1, sites.size()); +// +// +// sites = this.siteService.findSites("n3w s1t3 99", 0); +// assertNotNull(sites); +// assertEquals("Matched wrong number of sites for tokenized search", 1, sites.size()); + + sites = this.siteService.findSites("n3w s1t3", 0); + assertNotNull(sites); + assertEquals("Matched wrong number of sites for tokenized search", 2, sites.size()); + + sites = this.siteService.findSites("s1t3", 0); + assertNotNull(sites); + assertEquals("Matched wrong number of sites for tokenized search", 2, sites.size()); + + sites = this.siteService.findSites("super", 0); + assertNotNull(sites); + assertEquals("Matched wrong number of sites for super", 2, sites.size()); + + sites = this.siteService.findSites("exciting", 0); + assertNotNull(sites); + assertEquals("Matched wrong number of sites for exciting", 2, sites.size()); + + sites = this.siteService.findSites("product", 0); + assertNotNull(sites); + assertEquals("Matched wrong number of sites for product", 1, sites.size()); + +// sites = this.siteService.findSites("super product", 0); +// assertNotNull(sites); +// assertEquals("Matched wrong number of sites for super product", 1, sites.size()); +// +// sites = this.siteService.findSites("super launch", 0); +// assertNotNull(sites); +// assertEquals("Matched wrong number of sites for super launch", 1, sites.size()); + +// sites = this.siteService.findSites("exciting launch", 0); +// assertNotNull(sites); +// assertEquals("Matched wrong number of sites for super launch", 1, sites.size()); + + sites = this.siteService.findSites("super exciting", 0); + assertNotNull(sites); + assertEquals("Matched wrong number of sites for super exciting", 2, sites.size()); + + sites = this.siteService.findSites("amazing sales 54", 0); + assertNotNull(sites); + assertEquals("Matched wrong number of sites for amazing sales 54", 1, sites.size()); + + sites = this.siteService.findSites("wonderfulsupport32", 0); + assertNotNull(sites); + assertEquals("Matched wrong number of sites for wonderfulsupport32", 1, sites.size()); + + sites = this.siteService.findSites("great89service", 0); + assertNotNull(sites); + assertEquals("Matched wrong number of sites for great89service", 1, sites.size()); + + sites = this.siteService.findSites("top draw", 0); + assertNotNull(sites); + assertEquals("Matched wrong number of sites for top draw", 1, sites.size()); + } + public void testGetSite() { // Get a site that isn't there