diff --git a/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-query/pom.xml b/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-query/pom.xml index 7f8cf6b680b55df88c01ba563e5132c6a4dad366..dbf1a4c013ab2edc9cc10b601e778862428d013f 100644 --- a/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-query/pom.xml +++ b/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-query/pom.xml @@ -52,5 +52,24 @@ <artifactId>xwiki-platform-search-solr-api</artifactId> <version>${project.version}</version> </dependency> + <dependency> + <!-- Used to access the list of supported locales from the configuration of the current wiki. --> + <groupId>org.xwiki.platform</groupId> + <artifactId>xwiki-platform-oldcore</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <!-- Required for MockitoOldcoreRule. --> + <groupId>org.xwiki.platform</groupId> + <artifactId>xwiki-platform-oldcore</artifactId> + <version>${project.version}</version> + <classifier>tests</classifier> + <scope>test</scope> + </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>servlet-api</artifactId> + <scope>test</scope> + </dependency> </dependencies> </project> \ No newline at end of file diff --git a/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-query/src/main/java/org/xwiki/query/solr/internal/SolrQueryExecutor.java b/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-query/src/main/java/org/xwiki/query/solr/internal/SolrQueryExecutor.java index e96e96861564da65ac7bdba305fb0203b9a1efd9..19c3e64f904c6bc06bcc251feff63450ca4b3207 100644 --- a/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-query/src/main/java/org/xwiki/query/solr/internal/SolrQueryExecutor.java +++ b/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-query/src/main/java/org/xwiki/query/solr/internal/SolrQueryExecutor.java @@ -30,6 +30,7 @@ import javax.inject.Provider; import javax.inject.Singleton; +import org.apache.commons.lang.StringUtils; import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.response.QueryResponse; import org.apache.solr.common.SolrDocument; @@ -37,7 +38,6 @@ import org.slf4j.Logger; import org.xwiki.bridge.DocumentAccessBridge; import org.xwiki.component.annotation.Component; -import org.xwiki.configuration.ConfigurationSource; import org.xwiki.model.reference.DocumentReference; import org.xwiki.query.Query; import org.xwiki.query.QueryException; @@ -45,6 +45,8 @@ import org.xwiki.search.solr.internal.api.FieldUtils; import org.xwiki.search.solr.internal.api.SolrInstance; +import com.xpn.xwiki.XWikiContext; + /** * Executes Solr queries. * <p/> @@ -64,6 +66,12 @@ public class SolrQueryExecutor implements QueryExecutor */ public static final String SOLR = "solr"; + /** + * The parameter that specifies the list of supported locales. This is used to add generic (unlocalized) aliases for + * localized query fields (e.g. 'title' alias for 'title_en' query field). + */ + private static final String PARAM_SUPPORTED_LOCALES = "xwiki.supportedLocales"; + /** * Logging framework. */ @@ -77,49 +85,23 @@ public class SolrQueryExecutor implements QueryExecutor protected DocumentAccessBridge documentAccessBridge; /** - * Used to retrieve user preference regarding hidden documents. + * Provider for the {@link SolrInstance} that allows communication with the Solr server. */ @Inject - @Named("user") - protected ConfigurationSource userPreferencesSource; + protected Provider<SolrInstance> solrInstanceProvider; /** - * Provider for the {@link SolrInstance} that allows communication with the Solr server. + * Used to retrieve the configured supported locales. */ @Inject - protected Provider<SolrInstance> solrInstanceProvider; + private Provider<XWikiContext> xcontextProvider; @Override public <T> List<T> execute(Query query) throws QueryException { try { SolrInstance solrInstance = solrInstanceProvider.get(); - - SolrQuery solrQuery = new SolrQuery(query.getStatement()); - - // Overwrite offset and limit only if the query object explicitly says so, otherwise use whatever the query - // statement says or the defaults - if (query.getOffset() > 0) { - solrQuery.setStart(query.getOffset()); - } - if (query.getLimit() > 0) { - solrQuery.setRows(query.getLimit()); - } - - // TODO: good idea? Any confusion? Do we really needs something like this? - // Reuse the Query.getNamedParameters() map to get extra parameters. - for (Entry<String, Object> entry : query.getNamedParameters().entrySet()) { - Object value = entry.getValue(); - - if (value instanceof Iterable) { - solrQuery.set(entry.getKey(), toStringArray((Iterable) value)); - } else if (value != null && value.getClass().isArray()) { - solrQuery.set(entry.getKey(), toStringArray(value)); - } else { - solrQuery.set(entry.getKey(), String.valueOf(value)); - } - } - + SolrQuery solrQuery = createSolrQuery(query); QueryResponse response = solrInstance.query(solrQuery); // Check access rights need to be checked before returning the response. @@ -137,6 +119,45 @@ public <T> List<T> execute(Query query) throws QueryException } } + private SolrQuery createSolrQuery(Query query) + { + SolrQuery solrQuery = new SolrQuery(query.getStatement()); + + // Overwrite offset and limit only if the query object explicitly says so, otherwise use whatever the query + // statement says or the defaults. + if (query.getOffset() > 0) { + solrQuery.setStart(query.getOffset()); + } + if (query.getLimit() > 0) { + solrQuery.setRows(query.getLimit()); + } + + // TODO: good idea? Any confusion? Do we really needs something like this? + // Reuse the Query.getNamedParameters() map to get extra parameters. + for (Entry<String, Object> entry : query.getNamedParameters().entrySet()) { + Object value = entry.getValue(); + + if (value instanceof Iterable) { + solrQuery.set(entry.getKey(), toStringArray((Iterable) value)); + } else if (value != null && value.getClass().isArray()) { + solrQuery.set(entry.getKey(), toStringArray(value)); + } else { + solrQuery.set(entry.getKey(), String.valueOf(value)); + } + } + + // Make sure the list of supported locales is set so the names of the fields that are indexed in multiple + // languages are expanded in the search query. For instance, the query "title:text" will be expanded to + // "title__:text OR title_en:text OR title_fr:text" if the list of supported locales is [en, fr]. + if (!solrQuery.getParameterNames().contains(PARAM_SUPPORTED_LOCALES)) { + XWikiContext xcontext = this.xcontextProvider.get(); + solrQuery.set(PARAM_SUPPORTED_LOCALES, + StringUtils.join(xcontext.getWiki().getAvailableLocales(xcontext), ",")); + } + + return solrQuery; + } + /** * Converts an arbitrary array to an array containing its string representations. * diff --git a/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-query/src/test/java/org/xwiki/query/solr/SolrQueryExecutorTest.java b/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-query/src/test/java/org/xwiki/query/solr/SolrQueryExecutorTest.java index b73327236ba5abb0cfbdcd84a53966c54d9f0156..4a1822537af033aceb3d7fefd78d6fb151bf41eb 100644 --- a/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-query/src/test/java/org/xwiki/query/solr/SolrQueryExecutorTest.java +++ b/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-query/src/test/java/org/xwiki/query/solr/SolrQueryExecutorTest.java @@ -21,6 +21,7 @@ import java.lang.reflect.ParameterizedType; import java.util.Arrays; +import java.util.Locale; import javax.inject.Provider; @@ -44,9 +45,11 @@ import org.xwiki.test.annotation.ComponentList; import org.xwiki.test.mockito.MockitoComponentMockingRule; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import com.xpn.xwiki.XWikiContext; +import com.xpn.xwiki.test.MockitoOldcoreRule; + +import static org.mockito.Matchers.*; +import static org.mockito.Mockito.*; /** * Basic test for the {@link SolrQueryExecutor}. @@ -56,10 +59,9 @@ @ComponentList({DefaultQueryManager.class, DefaultQueryExecutorManager.class, ContextComponentManagerProvider.class}) public class SolrQueryExecutorTest { - private static final String ITERABLE_PARAM_NAME = "multiParam"; private static final String[] ITERABLE_PARAM_EXPECTED = {"value1", "value2"}; - private static final Iterable ITERABLE_PARAM_VALUE = Arrays.asList(ITERABLE_PARAM_EXPECTED); + private static final Iterable<String> ITERABLE_PARAM_VALUE = Arrays.asList(ITERABLE_PARAM_EXPECTED); private static final String INT_ARR_PARAM_NAME = "intArrayParam"; private static final String[] INT_ARR_PARAM_EXPECTED = {"-42", "4711"}; @@ -73,10 +75,12 @@ public class SolrQueryExecutorTest private static final Object SINGLE_PARAM_VALUE = new Object(); private static final Object SINGLE_PARAM_EXPECTED = SINGLE_PARAM_VALUE.toString(); - @Rule public final MockitoComponentMockingRule<QueryExecutor> componentManager = new MockitoComponentMockingRule<QueryExecutor>(SolrQueryExecutor.class); + @Rule + public final MockitoOldcoreRule oldCore = new MockitoOldcoreRule(this.componentManager); + @Test public void testExecutorRegistration() throws Exception { @@ -99,6 +103,9 @@ public Object answer(InvocationOnMock invocation) throws Throwable { Assert.assertArrayEquals(STR_ARR_PARAM_EXPECTED, solrQuery.getParams(STR_ARR_PARAM_NAME)); Assert.assertEquals(SINGLE_PARAM_EXPECTED, solrQuery.get(SINGLE_PARAM_NAME)); + // Check that the default list of supported locales is taken from the wiki configuration. + Assert.assertEquals("en,fr,de", solrQuery.get("xwiki.supportedLocales")); + QueryResponse r = mock(QueryResponse.class); when(r.getResults()).thenReturn(new SolrDocumentList()); return r; @@ -115,6 +122,11 @@ public Object answer(InvocationOnMock invocation) throws Throwable { query.bindValue(STR_ARR_PARAM_NAME, STR_ARR_PARAM_VALUE); query.bindValue(SINGLE_PARAM_NAME, SINGLE_PARAM_VALUE); + // The default list of supported locales should be taken from the wiki configuration. + XWikiContext xcontext = this.oldCore.getXWikiContext(); + when(this.oldCore.getMockXWiki().getAvailableLocales(xcontext)).thenReturn( + Arrays.asList(Locale.ENGLISH, Locale.FRENCH, Locale.GERMAN)); + componentManager.getComponentUnderTest().execute(query); } } diff --git a/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-rest/pom.xml b/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-rest/pom.xml index b779b14078b203dd072ce43654cf2ddab6627330..9ea32fe43c24e25e017bc37bce2459e366270339 100644 --- a/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-rest/pom.xml +++ b/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-rest/pom.xml @@ -37,11 +37,6 @@ <xwiki.jacoco.instructionRatio>0.0</xwiki.jacoco.instructionRatio> </properties> <dependencies> - <dependency> - <groupId>org.xwiki.platform</groupId> - <artifactId>xwiki-platform-oldcore</artifactId> - <version>${project.version}</version> - </dependency> <dependency> <groupId>org.xwiki.platform</groupId> <artifactId>xwiki-platform-rest-server</artifactId> diff --git a/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-rest/src/main/java/org/xwiki/search/solr/internal/rest/SOLRSearchSource.java b/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-rest/src/main/java/org/xwiki/search/solr/internal/rest/SOLRSearchSource.java index dbe668aa9c7cbc88c194c066a0868d7cbed9c330..53806b4faae2532ed68a21847393fab121a61f3c 100644 --- a/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-rest/src/main/java/org/xwiki/search/solr/internal/rest/SOLRSearchSource.java +++ b/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-rest/src/main/java/org/xwiki/search/solr/internal/rest/SOLRSearchSource.java @@ -27,7 +27,6 @@ import javax.inject.Inject; import javax.inject.Named; -import javax.inject.Provider; import javax.inject.Singleton; import javax.ws.rs.core.UriInfo; @@ -48,7 +47,6 @@ import org.xwiki.rest.resources.pages.PageResource; import org.xwiki.rest.resources.pages.PageTranslationResource; -import com.xpn.xwiki.XWikiContext; import com.xpn.xwiki.XWikiException; /** @@ -60,9 +58,6 @@ @Singleton public class SOLRSearchSource extends AbstractSearchSource { - @Inject - protected Provider<XWikiContext> xcontextProvider; - @Inject protected QueryManager queryManager; @@ -117,11 +112,6 @@ public List<SearchResult> search(String queryString, String defaultWikiName, Str } } - // Supported locales - XWikiContext xcontext = this.xcontextProvider.get(); - query.bindValue("xwiki.supportedLocales", - StringUtils.join(xcontext.getWiki().getAvailableLocales(xcontext), ',')); - // TODO: current locale filtering ? query.bindValue("fq", fq); diff --git a/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-ui/src/main/resources/Main/SolrSearch.xml b/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-ui/src/main/resources/Main/SolrSearch.xml index 9db5e92e3c11c4b179b79f6b61eb6282fcd46197..7f2b3f9c3f2e1a28afde5f9d24f8223081d9ce84 100644 --- a/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-ui/src/main/resources/Main/SolrSearch.xml +++ b/xwiki-platform-core/xwiki-platform-search/xwiki-platform-search-solr/xwiki-platform-search-solr-ui/src/main/resources/Main/SolrSearch.xml @@ -578,7 +578,6 @@ #set ($discard = $query.setLimit($rows)) #set ($discard = $query.setOffset($start)) #set ($discard = $query.bindValue('sort', "${sort} ${sortOrder}")) - #setSupportedLocales($query) #setQueryFields($query) #setFacetFields($query) #setFilterQuery($query) @@ -590,27 +589,6 @@ #set ($searchResponse = $query.execute()[0]) #end -#** - * We have to set the list of supported locales so the names of the fields that are indexed in multiple languages are - * expanded in the search query. For instance, the query "title:text" will be expanded to "title__:text OR - * title_en:text OR title_fr:text" if the list of supported locales is [en, fr]. - *# -#macro (setSupportedLocales $query) - #set ($supportedLanguagesRaw = $xwiki.getXWikiPreference('languages').split('[, |]')) - #set ($supportedLanguages = []) - #foreach ($supportedLanguage in $supportedLanguagesRaw) - #if ($supportedLanguage.trim() != '') - #set ($discard = $supportedLanguages.add($supportedLanguage)) - #end - #end - ## Make sure the default language is included. - #set ($defaultLanguage = $xwiki.getXWikiPreference('default_language', 'en')) - #if (!$supportedLanguages.contains($defaultLanguage)) - #set ($discard = $supportedLanguages.add($defaultLanguage)) - #end - #set ($discard = $query.bindValue('xwiki.supportedLocales', $stringtool.join($supportedLanguages, ','))) -#end - #macro (setQueryFields $query) ## Specify which index fields are matched when a free text search is performed. #if ($boost == '')