From c7bcfd00a4d0c562020ac0131eaeb5c4873c1ec5 Mon Sep 17 00:00:00 2001 From: Kevin Roast Date: Thu, 16 Jul 2009 10:27:09 +0000 Subject: [PATCH] Added query template support to the new JavaScript Search API. - JavaScript search query now supports adding query templates to the query definition object: search { query: string, store: string, language: string, templates: [], optional, Array of query language template objects (see below) sort: [], page: object } template { field: string, mandatory, custom field name for the template template: string mandatory, query template replacement for the template } see http://wiki.alfresco.com/wiki/Full_Text_Search_Query_Syntax#Templates git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@15221 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../org/alfresco/repo/jscript/Search.java | 144 ++++++++++++++---- 1 file changed, 111 insertions(+), 33 deletions(-) diff --git a/source/java/org/alfresco/repo/jscript/Search.java b/source/java/org/alfresco/repo/jscript/Search.java index d4202153ed..039ffc0efb 100644 --- a/source/java/org/alfresco/repo/jscript/Search.java +++ b/source/java/org/alfresco/repo/jscript/Search.java @@ -27,6 +27,7 @@ package org.alfresco.repo.jscript; import java.io.Serializable; import java.io.StringReader; import java.util.Collection; +import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; @@ -67,16 +68,16 @@ import com.werken.saxpath.XPathReader; * * @author Kevin Roast */ -public final class Search extends BaseScopableProcessorExtension +public class Search extends BaseScopableProcessorExtension { /** Service registry */ - private ServiceRegistry services; + protected ServiceRegistry services; /** Default store reference */ - private StoreRef storeRef; + protected StoreRef storeRef; /** Repository helper */ - private Repository repository; + protected Repository repository; /** @@ -433,6 +434,7 @@ public final class Search extends BaseScopableProcessorExtension * query: string, mandatory, in appropriate format and encoded for the given language * store: string, optional, defaults to 'workspace://SpacesStore' * language: string, optional, one of: lucene, xpath, jcr-xpath, fts-alfresco - defaults to 'lucene' + * templates: [], optional, Array of query language template objects (see below) * sort: [], optional, Array of sort column objects (see below) * page: object optional, paging information object (see below) - if supported by the language * } @@ -448,6 +450,16 @@ public final class Search extends BaseScopableProcessorExtension * maxItems: int, optional, max number of items to return in result set * skipCount: int optional, number of items to skip over before returning results * } + * + * template + * { + * field: string, mandatory, custom field name for the template + * template: string mandatory, query template replacement for the template + * } + * + * Note that only some query languages support custom query templates, such as 'fts-alfresco'. + * See the following documentation for more details: + * {@link http://wiki.alfresco.com/wiki/Full_Text_Search_Query_Syntax#Templates} * * * @param search Search definition object as above @@ -514,8 +526,59 @@ public final class Search extends BaseScopableProcessorExtension } } + // query templates + Map queryTemplates = null; + List> templates = (List>)def.get("templates"); + if (templates != null) + { + queryTemplates = new HashMap(templates.size(), 1.0f); + + for (Map template : templates) + { + String field = (String)template.get("field"); + if (field == null || field.length() == 0) + { + throw new AlfrescoRuntimeException("Failed to search: Missing mandatory 'template: field' value."); + } + String t = (String)template.get("template"); + if (t == null || t.length() == 0) + { + throw new AlfrescoRuntimeException("Failed to search: Missing mandatory 'template: template' value."); + } + queryTemplates.put(field, t); + } + } + + SearchParameters sp = new SearchParameters(); + sp.addStore(store != null ? new StoreRef(store) : this.storeRef); + sp.setLanguage(language != null ? language : SearchService.LANGUAGE_LUCENE); + sp.setQuery(query); + if (maxResults > 0) + { + sp.setLimit(maxResults); + sp.setLimitBy(LimitBy.FINAL_SIZE); + } + if (skipResults > 0) + { + sp.setSkipCount(skipResults); + } + if (sort != null) + { + for (SortColumn sd : sortColumns) + { + sp.addSort(sd.column, sd.asc); + } + } + if (queryTemplates != null) + { + for (String field: queryTemplates.keySet()) + { + sp.addQueryTemplate(field, queryTemplates.get(field)); + } + } + // execute search based on search definition - results = query(store, query, sortColumns, language, maxResults, skipResults); + results = query(sp); } } @@ -564,7 +627,7 @@ public final class Search extends BaseScopableProcessorExtension * * @return Array of Node objects */ - private Object[] query(String store, String search, SortColumn[] sort, String language) + protected Object[] query(String store, String search, SortColumn[] sort, String language) { return query(store, search, sort, language, -1, 0); } @@ -584,7 +647,43 @@ public final class Search extends BaseScopableProcessorExtension * * @return Array of Node objects */ - private Object[] query(String store, String search, SortColumn[] sort, String language, int maxResults, int skipResults) + protected Object[] query(String store, String search, SortColumn[] sort, String language, int maxResults, int skipResults) + { + SearchParameters sp = new SearchParameters(); + sp.addStore(store != null ? new StoreRef(store) : this.storeRef); + sp.setLanguage(language != null ? language : SearchService.LANGUAGE_LUCENE); + sp.setQuery(search); + if (maxResults > 0) + { + sp.setLimit(maxResults); + sp.setLimitBy(LimitBy.FINAL_SIZE); + } + if (skipResults > 0) + { + sp.setSkipCount(skipResults); + } + if (sort != null) + { + for (SortColumn sd : sort) + { + sp.addSort(sd.column, sd.asc); + } + } + + return query(sp); + } + + /** + * Execute the query + * + * Removes any duplicates that may be present (ID search can cause duplicates - + * it is better to remove them here) + * + * @param sp SearchParameters describing the search to execute. + * + * @return Array of Node objects + */ + protected Object[] query(SearchParameters sp) { Collection set = null; @@ -592,27 +691,6 @@ public final class Search extends BaseScopableProcessorExtension ResultSet results = null; try { - SearchParameters sp = new SearchParameters(); - sp.addStore(store != null ? new StoreRef(store) : this.storeRef); - sp.setLanguage(language != null ? language : SearchService.LANGUAGE_LUCENE); - sp.setQuery(search); - if (maxResults > 0) - { - sp.setLimit(maxResults); - sp.setLimitBy(LimitBy.FINAL_SIZE); - } - if (skipResults > 0) - { - sp.setSkipCount(skipResults); - } - if (sort != null) - { - for (SortColumn sd : sort) - { - sp.addSort(sd.column, sd.asc); - } - } - results = this.services.getSearchService().query(sp); if (results.length() != 0) @@ -627,7 +705,7 @@ public final class Search extends BaseScopableProcessorExtension } catch (Throwable err) { - throw new AlfrescoRuntimeException("Failed to execute search: " + search, err); + throw new AlfrescoRuntimeException("Failed to execute search: " + sp.getQuery(), err); } finally { @@ -639,12 +717,12 @@ public final class Search extends BaseScopableProcessorExtension return set != null ? set.toArray(new Object[(set.size())]) : new Object[0]; } - - + + /** * Search sort column */ - private class SortColumn + public class SortColumn { /** * Constructor @@ -652,7 +730,7 @@ public final class Search extends BaseScopableProcessorExtension * @param column column to sort on * @param asc sort direction */ - SortColumn(String column, boolean asc) + public SortColumn(String column, boolean asc) { this.column = column; this.asc = asc;