1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.rest.internal.resources

File BaseSearchResult.java

 

Coverage histogram

../../../../../img/srcFileCovDistChart9.png
38% of files have more coverage

Code metrics

66
222
6
2
586
396
54
0.24
37
3
9

Classes

Class Line # Actions
BaseSearchResult 57 222 0% 54 42
0.8571428785.7%
BaseSearchResult.SearchScope 65 0 - 0 0
-1.0 -
 

Contributing tests

No tests hitting this source file were found.

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package org.xwiki.rest.internal.resources;
21   
22    import java.util.ArrayList;
23    import java.util.Calendar;
24    import java.util.Formatter;
25    import java.util.List;
26   
27    import javax.inject.Inject;
28    import javax.inject.Named;
29    import javax.ws.rs.core.UriBuilderException;
30   
31    import org.apache.commons.lang3.StringUtils;
32    import org.xwiki.model.reference.SpaceReference;
33    import org.xwiki.query.Query;
34    import org.xwiki.query.QueryException;
35    import org.xwiki.query.QueryFilter;
36    import org.xwiki.rest.Relations;
37    import org.xwiki.rest.XWikiResource;
38    import org.xwiki.rest.internal.Utils;
39    import org.xwiki.rest.internal.resources.search.SearchSource;
40    import org.xwiki.rest.model.jaxb.Link;
41    import org.xwiki.rest.model.jaxb.SearchResult;
42    import org.xwiki.rest.resources.objects.ObjectResource;
43    import org.xwiki.rest.resources.pages.PageResource;
44    import org.xwiki.rest.resources.pages.PageTranslationResource;
45    import org.xwiki.rest.resources.spaces.SpaceResource;
46    import org.xwiki.security.authorization.ContextualAuthorizationManager;
47    import org.xwiki.security.authorization.Right;
48   
49    import com.xpn.xwiki.XWikiContext;
50    import com.xpn.xwiki.XWikiException;
51    import com.xpn.xwiki.api.Document;
52    import com.xpn.xwiki.api.XWiki;
53   
54    /**
55    * @version $Id: c99f630c8f3d5babc266d72cb2d37bf7bccaebe8 $
56    */
 
57    public class BaseSearchResult extends XWikiResource
58    {
59    protected static final String SEARCH_TEMPLATE_INFO =
60    "q={keywords}(&scope={content|name|title|spaces|objects})*(&number={number})(&start={start})(&orderField={fieldname}(&order={asc|desc}))(&prettyNames={false|true})";
61   
62    protected static final String QUERY_TEMPLATE_INFO =
63    "q={query}(&type={type})(&number={number})(&start={start})(&orderField={fieldname}(&order={asc|desc}))(&distinct=1)(&prettyNames={false|true})(&wikis={wikis})(&className={classname})";
64   
 
65    protected enum SearchScope
66    {
67    SPACES,
68    NAME,
69    CONTENT,
70    TITLE,
71    OBJECTS
72    }
73   
74    @Inject
75    private ContextualAuthorizationManager authorizationManager;
76   
77    @Inject
78    @Named("hidden/space")
79    private QueryFilter hiddenSpaceFilter;
80   
81    /**
82    * Search for keyword in the given scopes. See {@link SearchScope} for more information.
83    *
84    * @param number number of results to be returned.
85    * @param start 0-based start offset.
86    * @param withPrettyNames true if the users are displayed with their full name
87    */
 
88  36 toggle protected List<SearchResult> search(List<SearchScope> searchScopes, String keywords, String wikiName, String space,
89    boolean hasProgrammingRights, int number, int start, boolean distinct, String orderField, String order,
90    Boolean withPrettyNames) throws IllegalArgumentException, UriBuilderException, QueryException, XWikiException
91    {
92  36 String database = Utils.getXWikiContext(componentManager).getWikiId();
93   
94    /* This try is just needed for executing the finally clause. */
95  36 try {
96  36 if (wikiName != null) {
97  36 Utils.getXWikiContext(componentManager).setWikiId(wikiName);
98    }
99   
100  36 List<SearchResult> result = new ArrayList<SearchResult>();
101   
102  36 result.addAll(searchPages(searchScopes, keywords, wikiName, space, hasProgrammingRights, number, start,
103    orderField, order, withPrettyNames));
104   
105  36 if (searchScopes.contains(SearchScope.SPACES)) {
106  17 result.addAll(searchSpaces(keywords, wikiName, number, start));
107    }
108   
109  36 if (searchScopes.contains(SearchScope.OBJECTS)) {
110  2 result.addAll(searchObjects(keywords, wikiName, space, hasProgrammingRights, number, start, orderField,
111    order, withPrettyNames));
112    }
113   
114  36 return result;
115    } finally {
116  36 Utils.getXWikiContext(componentManager).setWikiId(database);
117    }
118    }
119   
120    /**
121    * Search for keyword in the given scopes. Limit the search only to Pages. Search for keyword
122    *
123    * @param keywords the string that will be used in a "like" XWQL clause.
124    * @param number number of results to be returned.
125    * @param start 0-based start offset.
126    * @param orderField the field to be used to order the results.
127    * @param order "asc" or "desc"
128    * @return the results.
129    */
 
130  36 toggle protected List<SearchResult> searchPages(List<SearchScope> searchScopes, String keywords, String wikiName,
131    String space, boolean hasProgrammingRights, int number, int start, String orderField, String order,
132    Boolean withPrettyNames) throws QueryException, IllegalArgumentException, UriBuilderException, XWikiException
133    {
134  36 XWiki xwikiApi = Utils.getXWikiApi(componentManager);
135   
136  36 String database = Utils.getXWikiContext(componentManager).getWikiId();
137   
138    /* This try is just needed for executing the finally clause. */
139  36 try {
140  36 List<SearchResult> result = new ArrayList<SearchResult>();
141   
142  36 if (keywords == null) {
143  10 return result;
144    }
145   
146  26 Formatter f = new Formatter();
147   
148    /*
149    * If the order field is already one of the field hard coded in the base query, then do not add it to the
150    * select clause.
151    */
152  26 String addColumn = "";
153  26 if (!StringUtils.isBlank(orderField)) {
154  0 addColumn =
155  0 (orderField.equals("") || orderField.equals("fullName") || orderField.equals("name") || orderField
156    .equals("space")) ? "" : ", doc." + orderField;
157    }
158   
159  26 if (space != null) {
160  2 f.format("select distinct doc.fullName, doc.space, doc.name, doc.language");
161  2 f.format(addColumn);
162  2 f.format(" from XWikiDocument as doc where doc.space = :space and ( ");
163    } else {
164  24 f.format("select distinct doc.fullName, doc.space, doc.name, doc.language");
165  24 f.format(addColumn);
166  24 f.format(" from XWikiDocument as doc where ( ");
167    }
168   
169    /* Look for scopes related to pages */
170  26 int acceptedScopes = 0;
171  52 for (int i = 0; i < searchScopes.size(); i++) {
172  26 SearchScope scope = searchScopes.get(i);
173   
174  26 switch (scope) {
175  3 case CONTENT:
176  3 f.format("upper(doc.content) like :keywords ");
177  3 acceptedScopes++;
178  3 break;
179  3 case NAME:
180  3 f.format("upper(doc.fullName) like :keywords ");
181  3 acceptedScopes++;
182  3 break;
183  1 case TITLE:
184  1 f.format("upper(doc.title) like :keywords ");
185  1 acceptedScopes++;
186  1 break;
187    }
188   
189  26 if (i != searchScopes.size() - 1) {
190  0 f.format(" or ");
191    }
192    }
193   
194    /* If we don't find any scope related to pages then return empty results */
195  26 if (acceptedScopes == 0) {
196  19 return result;
197    }
198   
199    /* Build the order clause. */
200  7 String orderClause = null;
201  7 if (StringUtils.isBlank(orderField)) {
202  7 orderClause = "doc.fullName asc";
203    } else {
204    /* Check if the order parameter is a valid "asc" or "desc" string, otherwise use "asc" */
205  0 if ("asc".equals(order) || "desc".equals(order)) {
206  0 orderClause = String.format("doc.%s %s", orderField, order);
207    } else {
208  0 orderClause = String.format("doc.%s asc", orderField);
209    }
210    }
211   
212    // Add ordering
213  7 f.format(") order by %s", orderClause);
214   
215  7 String query = f.toString();
216   
217  7 List<Object> queryResult = null;
218   
219    /* This is needed because if the :space placeholder is not in the query, setting it would cause an exception */
220  7 if (space != null) {
221  2 queryResult =
222    this.queryManager.createQuery(query, Query.XWQL)
223    .bindValue("keywords", String.format("%%%s%%", keywords.toUpperCase()))
224    .bindValue("space", space).addFilter(Utils.getHiddenQueryFilter(this.componentManager))
225    .setOffset(start).setLimit(number).execute();
226    } else {
227  5 queryResult =
228    this.queryManager.createQuery(query, Query.XWQL)
229    .bindValue("keywords", String.format("%%%s%%", keywords.toUpperCase()))
230    .addFilter(Utils.getHiddenQueryFilter(this.componentManager)).setOffset(start).setLimit(number)
231    .execute();
232    }
233   
234  7 for (Object object : queryResult) {
235  8 Object[] fields = (Object[]) object;
236   
237  8 String spaceId = (String) fields[1];
238  8 List<String> spaces = Utils.getSpacesFromSpaceId(spaceId);
239  8 String pageName = (String) fields[2];
240  8 String language = (String) fields[3];
241   
242  8 String pageId = Utils.getPageId(wikiName, spaces, pageName);
243  8 String pageFullName = Utils.getPageFullName(wikiName, spaces, pageName);
244   
245    /* Check if the user has the right to see the found document */
246  8 if (xwikiApi.hasAccessLevel("view", pageId)) {
247  8 Document doc = xwikiApi.getDocument(pageFullName);
248  8 String title = doc.getDisplayTitle();
249  8 SearchResult searchResult = objectFactory.createSearchResult();
250  8 searchResult.setType("page");
251  8 searchResult.setId(pageId);
252  8 searchResult.setPageFullName(pageFullName);
253  8 searchResult.setTitle(title);
254  8 searchResult.setWiki(wikiName);
255  8 searchResult.setSpace(spaceId);
256  8 searchResult.setPageName(pageName);
257  8 searchResult.setVersion(doc.getVersion());
258  8 searchResult.setAuthor(doc.getAuthor());
259  8 Calendar calendar = Calendar.getInstance();
260  8 calendar.setTime(doc.getDate());
261  8 searchResult.setModified(calendar);
262   
263  8 if (withPrettyNames) {
264  0 searchResult.setAuthorName(Utils.getAuthorName(doc.getAuthorReference(), componentManager));
265    }
266   
267  8 String pageUri = null;
268  8 if (StringUtils.isBlank(language)) {
269  8 pageUri =
270    Utils.createURI(this.uriInfo.getBaseUri(), PageResource.class, wikiName, spaces,
271    pageName).toString();
272    } else {
273  0 searchResult.setLanguage(language);
274  0 pageUri =
275    Utils.createURI(this.uriInfo.getBaseUri(), PageTranslationResource.class, wikiName,
276    spaces, pageName, language).toString();
277    }
278   
279  8 Link pageLink = new Link();
280  8 pageLink.setHref(pageUri);
281  8 pageLink.setRel(Relations.PAGE);
282  8 searchResult.getLinks().add(pageLink);
283   
284  8 result.add(searchResult);
285    }
286    }
287   
288  7 return result;
289    } finally {
290  36 Utils.getXWikiContext(componentManager).setWikiId(database);
291    }
292    }
293   
294    /**
295    * Search for keyword in the given scopes. Limit the search only to spaces.
296    *
297    * @param keywords the string that will be used in a "like" XWQL clause
298    * @param number number of results to be returned
299    * @param start 0-based start offset
300    * @return the results.
301    */
 
302  17 toggle protected List<SearchResult> searchSpaces(String keywords, String wikiName, int number, int start)
303    throws QueryException, IllegalArgumentException, UriBuilderException, XWikiException
304    {
305  17 List<SearchResult> result = new ArrayList<SearchResult>();
306   
307  17 if (StringUtils.isEmpty(keywords)) {
308  0 return result;
309    }
310  17 String escapedKeywords = keywords.replaceAll("([%_!])", "!$1");
311   
312  17 String query = "select space.reference from XWikiSpace as space"
313    + " where lower(space.name) like lower(:keywords) escape '!'"
314    + " or lower(space.reference) like lower(:prefix) escape '!'"
315    + " order by lower(space.reference), space.reference";
316   
317  17 List<Object> queryResult = queryManager.createQuery(query, Query.HQL)
318    .bindValue("keywords", String.format("%%%s%%", escapedKeywords))
319    .bindValue("prefix", String.format("%s%%", escapedKeywords))
320    .setWiki(wikiName).setLimit(number).setOffset(start)
321    .addFilter(this.hiddenSpaceFilter).execute();
322   
323  17 XWiki xwikiApi = Utils.getXWikiApi(componentManager);
324  17 for (Object object : queryResult) {
325  27 String spaceId = (String) object;
326  27 List<String> spaces = Utils.getSpacesFromSpaceId(spaceId);
327  27 SpaceReference spaceReference = new SpaceReference(wikiName, spaces);
328   
329  27 if (this.authorizationManager.hasAccess(Right.VIEW, spaceReference)) {
330  27 Document spaceDoc = xwikiApi.getDocument(spaceReference);
331   
332  27 SearchResult searchResult = objectFactory.createSearchResult();
333  27 searchResult.setType("space");
334  27 searchResult.setId(spaceId);
335  27 searchResult.setWiki(wikiName);
336  27 searchResult.setSpace(spaceId);
337  27 searchResult.setTitle(spaceDoc != null ? spaceDoc.getPlainTitle() : spaceReference.getName());
338   
339    // Add a link to the space information.
340  27 Link spaceLink = new Link();
341  27 spaceLink.setRel(Relations.SPACE);
342  27 spaceLink.setHref(Utils.createURI(uriInfo.getBaseUri(), SpaceResource.class, wikiName, spaces)
343    .toString());
344  27 searchResult.getLinks().add(spaceLink);
345   
346    // Add a link to the home page if it exists and it is viewable.
347  27 if (spaceDoc != null && !spaceDoc.isNew()) {
348  14 Link pageLink = new Link();
349  14 pageLink.setHref(Utils.createURI(uriInfo.getBaseUri(), PageResource.class, wikiName, spaces,
350    spaceDoc.getName()).toString());
351  14 pageLink.setRel(Relations.HOME);
352  14 searchResult.getLinks().add(pageLink);
353    }
354   
355  27 result.add(searchResult);
356    }
357    }
358   
359  17 return result;
360    }
361   
362    /**
363    * Search for keyword in the given scopes. Limit the search only to Objects.
364    *
365    * @param number number of results to be returned
366    * @param start 0-based start offset
367    * @param orderField the field to be used to order the results
368    * @param order "asc" or "desc"
369    * @return the results
370    */
 
371  2 toggle protected List<SearchResult> searchObjects(String keywords, String wikiName, String space,
372    boolean hasProgrammingRights, int number, int start, String orderField, String order, Boolean withPrettyNames)
373    throws QueryException, IllegalArgumentException, UriBuilderException, XWikiException
374    {
375  2 XWikiContext xwikiContext = Utils.getXWikiContext(componentManager);
376   
377  2 XWiki xwikiApi = Utils.getXWikiApi(componentManager);
378   
379  2 String database = Utils.getXWikiContext(componentManager).getWikiId();
380   
381    /* This try is just needed for executing the finally clause. */
382  2 try {
383  2 List<SearchResult> result = new ArrayList<SearchResult>();
384   
385  2 if (keywords == null) {
386  0 return result;
387    }
388   
389  2 Formatter f = new Formatter();
390   
391    /*
392    * If the order field is already one of the field hard coded in the base query, then do not add it to the
393    * select clause.
394    */
395  2 String addColumn =
396  2 (orderField.equals("") || orderField.equals("fullName") || orderField.equals("name") || orderField
397    .equals("space")) ? "" : ", doc." + orderField;
398   
399  2 if (space != null) {
400  0 f.format("select distinct doc.fullName, doc.space, doc.name, obj.className, obj.number");
401  0 f.format(addColumn);
402  0 f.format(" from XWikiDocument as doc, BaseObject as obj, StringProperty as sp, LargeStringProperty as lsp where doc.space = :space and obj.name=doc.fullName and sp.id.id = obj.id and lsp.id.id = obj.id and (upper(sp.value) like :keywords or upper(lsp.value) like :keywords) ");
403    } else {
404  2 f.format("select distinct doc.fullName, doc.space, doc.name, obj.className, obj.number");
405  2 f.format(addColumn);
406  2 f.format(" from XWikiDocument as doc, BaseObject as obj, StringProperty as sp, LargeStringProperty as lsp where obj.name=doc.fullName and sp.id.id = obj.id and lsp.id.id = obj.id and (upper(sp.value) like :keywords or upper(lsp.value) like :keywords) ");
407    }
408   
409    /* Build the order clause. */
410  2 String orderClause = null;
411  2 if (StringUtils.isBlank(orderField)) {
412  2 orderClause = "doc.fullName asc";
413    } else {
414    /* Check if the order parameter is a valid "asc" or "desc" string, otherwise use "asc" */
415  0 if ("asc".equals(order) || "desc".equals(order)) {
416  0 orderClause = String.format("doc.%s %s", orderField, order);
417    } else {
418  0 orderClause = String.format("doc.%s asc", orderField);
419    }
420    }
421   
422    /* Add some filters if the user doesn't have programming rights. */
423  2 if (hasProgrammingRights) {
424  1 f.format(" order by %s", orderClause);
425    } else {
426  1 f.format(
427    " and doc.space<>'XWiki' and doc.space<>'Admin' and doc.space<>'Panels' and doc.name<>'WebPreferences' order by %s",
428    orderClause);
429    }
430   
431  2 String query = f.toString();
432   
433  2 List<Object> queryResult = null;
434   
435    /* This is needed because if the :space placeholder is not in the query, setting it would cause an exception */
436  2 if (space != null) {
437  0 queryResult =
438    queryManager.createQuery(query, Query.XWQL)
439    .bindValue("keywords", String.format("%%%s%%", keywords.toUpperCase()))
440    .bindValue("space", space).setLimit(number).execute();
441    } else {
442  2 queryResult =
443    queryManager.createQuery(query, Query.XWQL)
444    .bindValue("keywords", String.format("%%%s%%", keywords.toUpperCase())).setLimit(number)
445    .execute();
446    }
447   
448    /* Build the result. */
449  2 for (Object object : queryResult) {
450  1 Object[] fields = (Object[]) object;
451   
452  1 String spaceId = (String) fields[1];
453  1 List<String> spaces = Utils.getSpacesFromSpaceId(spaceId);
454  1 String pageName = (String) fields[2];
455  1 String className = (String) fields[3];
456  1 int objectNumber = (Integer) fields[4];
457   
458  1 String id = Utils.getObjectId(wikiName, spaces, pageName, className, objectNumber);
459   
460  1 String pageId = Utils.getPageId(wikiName, spaces, pageName);
461  1 String pageFullName = Utils.getPageFullName(wikiName, spaces, pageName);
462   
463    /*
464    * Check if the user has the right to see the found document. We also prevent guest users to access
465    * object data in order to avoid leaking important information such as emails to crawlers.
466    */
467  1 if (xwikiApi.hasAccessLevel("view", pageId) && xwikiContext.getUserReference() != null) {
468  1 Document doc = xwikiApi.getDocument(pageFullName);
469  1 String title = doc.getDisplayTitle();
470  1 SearchResult searchResult = objectFactory.createSearchResult();
471  1 searchResult.setType("object");
472  1 searchResult.setId(id);
473  1 searchResult.setPageFullName(pageFullName);
474  1 searchResult.setTitle(title);
475  1 searchResult.setWiki(wikiName);
476  1 searchResult.setSpace(spaceId);
477  1 searchResult.setPageName(pageName);
478  1 searchResult.setVersion(doc.getVersion());
479  1 searchResult.setClassName(className);
480  1 searchResult.setObjectNumber(objectNumber);
481  1 searchResult.setAuthor(doc.getAuthor());
482  1 Calendar calendar = Calendar.getInstance();
483  1 calendar.setTime(doc.getDate());
484  1 searchResult.setModified(calendar);
485   
486  1 if (withPrettyNames) {
487  0 searchResult.setAuthorName(Utils.getAuthorName(doc.getAuthorReference(), componentManager));
488    }
489   
490  1 String pageUri =
491    Utils.createURI(uriInfo.getBaseUri(), PageResource.class, wikiName, spaces, pageName)
492    .toString();
493  1 Link pageLink = new Link();
494  1 pageLink.setHref(pageUri);
495  1 pageLink.setRel(Relations.PAGE);
496  1 searchResult.getLinks().add(pageLink);
497   
498  1 String objectUri =
499    Utils.createURI(uriInfo.getBaseUri(), ObjectResource.class, wikiName, spaces, pageName,
500    className, objectNumber).toString();
501  1 Link objectLink = new Link();
502  1 objectLink.setHref(objectUri);
503  1 objectLink.setRel(Relations.OBJECT);
504  1 searchResult.getLinks().add(objectLink);
505   
506  1 result.add(searchResult);
507    }
508    }
509   
510  2 return result;
511    } finally {
512  2 Utils.getXWikiContext(componentManager).setWikiId(database);
513    }
514    }
515   
516    /**
517    * Search for query using xwql, hql, lucene. Limit the search only to Pages. Search for keyword
518    *
519    * @param query the query to be executed
520    * @param queryTypeString can be "xwql", "hql" or "lucene".
521    * @param orderField the field to be used to order the results.
522    * @param order "asc" or "desc"
523    * @param number number of results to be returned
524    * @param start 0-based start offset.
525    * @return a list of {@link SearchResult} objects containing the found items, or an empty list if the specified
526    * query type string doesn't represent a supported query type.
527    */
 
528  5 toggle protected List<SearchResult> searchQuery(String query, String queryTypeString, String wikiName, String wikis,
529    boolean hasProgrammingRights, String orderField, String order, boolean distinct, int number, int start,
530    Boolean withPrettyNames, String className) throws Exception
531    {
532  5 String currentWiki = Utils.getXWikiContext(componentManager).getWikiId();
533   
534    /* This try is just needed for executing the finally clause. */
535  5 try {
536  5 if (wikiName != null) {
537  5 Utils.getXWikiContext(componentManager).setWikiId(wikiName);
538    }
539   
540  5 List<SearchResult> result;
541   
542  5 if (queryTypeString != null) {
543  4 SearchSource searchSource =
544    this.componentManager.getInstance(SearchSource.class, queryTypeString.toLowerCase());
545   
546  4 result =
547    searchSource.search(query, wikiName, wikis, hasProgrammingRights, orderField, order,
548    distinct, number, start, withPrettyNames, className, uriInfo);
549    } else {
550  1 result = new ArrayList<SearchResult>();
551    }
552   
553  5 return result;
554    } finally {
555  5 Utils.getXWikiContext(componentManager).setWikiId(currentWiki);
556    }
557    }
558   
559    /**
560    * Return a list of {@link SearchScope} objects by parsing the strings provided in the search scope strings. If the
561    * list doesn't contain any valid scope string, then CONTENT is added by default.
562    *
563    * @param searchScopeStrings The list of string to be parsed.
564    * @return The list of the parsed SearchScope elements.
565    */
 
566  36 toggle protected List<SearchScope> parseSearchScopeStrings(List<String> searchScopeStrings)
567    {
568  36 List<SearchScope> searchScopes = new ArrayList<SearchScope>();
569  36 for (String searchScopeString : searchScopeStrings) {
570  36 if (searchScopeString != null && !searchScopes.contains(searchScopeString)) {
571  23 try {
572  23 SearchScope searchScope = SearchScope.valueOf(searchScopeString.toUpperCase());
573  23 searchScopes.add(searchScope);
574    } catch (IllegalArgumentException e) {
575    // Ignore unrecognized scopes
576    }
577    }
578    }
579   
580  36 if (searchScopes.isEmpty()) {
581  13 searchScopes.add(SearchScope.CONTENT);
582    }
583   
584  36 return searchScopes;
585    }
586    }