diff --git a/src/main/java/org/springframework/data/solr/core/MulticoreSolrOperations.java b/src/main/java/org/springframework/data/solr/core/MulticoreSolrOperations.java new file mode 100644 index 000000000..186b85ed1 --- /dev/null +++ b/src/main/java/org/springframework/data/solr/core/MulticoreSolrOperations.java @@ -0,0 +1,446 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.solr.core; + +import java.io.Serializable; +import java.util.Collection; + +import org.apache.solr.client.solrj.SolrClient; +import org.apache.solr.client.solrj.response.SolrPingResponse; +import org.apache.solr.client.solrj.response.UpdateResponse; +import org.apache.solr.common.SolrInputDocument; +import org.springframework.data.solr.core.query.FacetQuery; +import org.springframework.data.solr.core.query.HighlightQuery; +import org.springframework.data.solr.core.query.Query; +import org.springframework.data.solr.core.query.SolrDataQuery; +import org.springframework.data.solr.core.query.TermsQuery; +import org.springframework.data.solr.core.query.result.Cursor; +import org.springframework.data.solr.core.query.result.FacetPage; +import org.springframework.data.solr.core.query.result.GroupPage; +import org.springframework.data.solr.core.query.result.HighlightPage; +import org.springframework.data.solr.core.query.result.ScoredPage; +import org.springframework.data.solr.core.query.result.StatsPage; +import org.springframework.data.solr.core.query.result.TermsPage; + +/** + * Interface that specifies a set of multicore Solr operations. + * + * @author Venil Noronha + */ +public interface MulticoreSolrOperations extends SolrOperations { + + /** + * Get the SolrClient instance for the given solr core. + * + * @param coreName + * + * @return + */ + SolrClient getSolrClient(String coreName); + + /** + * Execute ping against the given solr core and return duration in msec. + * + * @param coreName + * + * @return + */ + SolrPingResponse ping(String coreName); + + /** + * Return number of elements found by for given query against the given + * solr core. + * + * @param coreName + * @param query + * + * @return + */ + long count(String coreName, SolrDataQuery query); + + /** + * Return number of elements found by for given query against the given + * solr core. + * + * @param coreName + * @param query + * @param method + * + * @return + */ + long count(String coreName, SolrDataQuery query, RequestMethod method); + + /** + * Execute add operation against the given solr core, which will do either + * insert or update. + * + * @param coreName + * @param obj + * + * @return + */ + UpdateResponse saveBean(String coreName, Object obj); + + /** + * Execute add operation against the given solr core, which will do either + * insert or update with support for commitWithin strategy. + * + * @param coreName + * @param obj + * @param commitWithinMs + * + * @return + */ + UpdateResponse saveBean(String coreName, Object obj, int commitWithinMs); + + /** + * Add a collection of beans to the given solr core, which will do either + * insert or update. + * + * @param coreName + * @param beans + * + * @return + */ + UpdateResponse saveBeans(String coreName, Collection beans); + + /** + * Add a collection of beans to the given solr core, which will do either + * insert or update with support for commitWithin strategy. + * + * @param coreName + * @param beans + * @param commitWithinMs + * + * @return + */ + UpdateResponse saveBeans(String coreName, Collection beans, int commitWithinMs); + + /** + * Add a solrj input document to the given solr core, which will do either + * insert or update. + * + * @param coreName + * @param document + * + * @return + */ + UpdateResponse saveDocument(String coreName, SolrInputDocument document); + + /** + * Add a solrj input document to the given solr core, which will do either + * insert or update with support for commitWithin strategy. + * + * @param coreName + * @param document + * @param commitWithinMs + * + * @return + */ + UpdateResponse saveDocument(String coreName, SolrInputDocument document, int commitWithinMs); + + /** + * Add multiple solrj input documents to the given solr core, which will do + * either insert or update. + * + * @param coreName + * @param documents + * + * @return + */ + UpdateResponse saveDocuments(String coreName, Collection documents); + + /** + * Add multiple solrj input documents to the given solr core, which will do + * either insert or update with support for commitWithin strategy. + * + * @param coreName + * @param documents + * @param commitWithinMs + * + * @return + */ + UpdateResponse saveDocuments(String coreName, Collection documents, int commitWithinMs); + + /** + * Find and delete all objects matching the provided Query from the given + * solr core. + * + * @param coreName + * @param query + * + * @return + */ + UpdateResponse delete(String coreName, SolrDataQuery query); + + /** + * Delete the one object with provided id from the given solr core. + * + * @param coreName + * @param id + * + * @return + */ + UpdateResponse deleteById(String coreName, String id); + + /** + * Delete objects with given ids from the given solr core. + * + * @param coreName + * @param ids + * + * @return + */ + UpdateResponse deleteById(String coreName, Collection ids); + + /** + * Execute the query against the given solr core and return the + * first returned object. + * + * @param coreName + * @param query + * @param clazz + * + * @return the first matching object + */ + T queryForObject(String coreName, Query query, Class clazz); + + /** + * Execute the query against the given solr core and return the + * first returned object. + * + * @param coreName + * @param query + * @param clazz + * @param method + * + * @return the first matching object + */ + T queryForObject(String coreName, Query query, Class clazz, RequestMethod method); + + /** + * Execute the query against the given solr core and return result + * as Page. + * + * @param coreName + * @param query + * @param clazz + * + * @return + */ + ScoredPage queryForPage(String coreName, Query query, Class clazz); + + /** + * Execute the query against the given solr core and return result + * as Page. + * + * @param coreName + * @param query + * @param clazz + * @param method + * + * @return + */ + ScoredPage queryForPage(String coreName, Query query, Class clazz, RequestMethod method); + + /** + * Execute a facet query against the given solr core. Facet result + * will be returned along with query result within the FacetPage. + * + * @param coreName + * @param query + * @param clazz + * + * @return + */ + FacetPage queryForFacetPage(String coreName, FacetQuery query, Class clazz); + + /** + * Execute a facet query against the given solr core. Facet result + * will be returned along with query result within the FacetPage. + * + * @param coreName + * @param query + * @param clazz + * @param method + * + * @return + */ + FacetPage queryForFacetPage(String coreName, FacetQuery query, Class clazz, RequestMethod method); + + /** + * Execute a query against the given solr core and highlight matches + * in result. + * + * @param coreName + * @param query + * @param clazz + * + * @return + */ + HighlightPage queryForHighlightPage(String coreName, HighlightQuery query, Class clazz); + + /** + * Execute a query against the given solr core and highlight matches + * in result. + * + * @param coreName + * @param query + * @param clazz + * @param method + * + * @return + */ + HighlightPage queryForHighlightPage(String coreName, HighlightQuery query, Class clazz, RequestMethod method); + + /** + * Execute query against the given solr core using terms handler. + * + * @param coreName + * @param query + * + * @return + */ + TermsPage queryForTermsPage(String coreName, TermsQuery query); + + /** + * Execute query against the given solr core using terms handler. + * + * @param coreName + * @param query + * @param method + * + * @return + */ + TermsPage queryForTermsPage(String coreName, TermsQuery query, RequestMethod method); + + /** + * Executes the given Query against the given solr core and returns an + * open Cursor allowing to iterate of results, dynamically fetching + * additional ones if required. + * + * @param coreName + * @param query + * @param clazz + * + * @return + */ + Cursor queryForCursor(String coreName, Query query, Class clazz); + + /** + * Execute the query against the given solr core and return result as + * GroupPage. + * + * @param coreName + * @param query + * @param clazz + * + * @return + */ + GroupPage queryForGroupPage(String coreName, Query query, Class clazz); + + /** + * Execute the query against the given solr core and return result as + * GroupPage. + * + * @param coreName + * @param query + * @param clazz + * @param method + * + * @return + */ + GroupPage queryForGroupPage(String coreName, Query query, Class clazz, RequestMethod method); + + /** + * Execute the query against the given solr core and return result as + * StatsPage. + * + * @param coreName + * @param query + * @param clazz + * + * @return + */ + StatsPage queryForStatsPage(String coreName, Query query, Class clazz); + + /** + * Execute the query against the given solr core and return result as + * StatsPage. + * + * @param coreName + * @param query + * @param clazz + * @param method + * + * @return + */ + StatsPage queryForStatsPage(String coreName, Query query, Class clazz, RequestMethod method); + + /** + * Executes a realtime get against the given solr core using given id. + * + * @param coreName + * @param id + * @param clazz + * + * @return + */ + T getById(String coreName, Serializable id, Class clazz); + + /** + * Executes a realtime get against the given solr core using given ids. + * + * @param coreName + * @param ids + * @param clazz + * + * @return + */ + Collection getById(String coreName, Collection ids, Class clazz); + + /** + * Send commit command to the given solr core + * + * @param coreName + */ + void commit(String coreName); + + /** + * Send soft commit command to the given solr core. + * + * @param coreName + */ + void softCommit(String coreName); + + /** + * Send rollback command to the given solr core. + * + * @param coreName + */ + void rollback(String coreName); + + /** + * Execute action within callback against the given solr core. + * + * @param coreName + * @param action + * + * @return + */ + T execute(String coreName, SolrCallback action); + +} diff --git a/src/main/java/org/springframework/data/solr/core/SolrOperations.java b/src/main/java/org/springframework/data/solr/core/SolrOperations.java index 5b86c68fb..888ea6dd9 100644 --- a/src/main/java/org/springframework/data/solr/core/SolrOperations.java +++ b/src/main/java/org/springframework/data/solr/core/SolrOperations.java @@ -156,7 +156,7 @@ public interface SolrOperations { UpdateResponse delete(SolrDataQuery query); /** - * Detele the one object with provided id + * Delete the one object with provided id * * @param id * @return @@ -192,7 +192,7 @@ public interface SolrOperations { T queryForObject(Query query, Class clazz, RequestMethod method); /** - * Execute the query against solr and retrun result as {@link Page} + * Execute the query against solr and return result as {@link Page} * * @param query * @param clazz @@ -201,7 +201,7 @@ public interface SolrOperations { ScoredPage queryForPage(Query query, Class clazz); /** - * Execute the query against solr and retrun result as {@link Page} + * Execute the query against solr and return result as {@link Page} * * @param query must not be {@literal null}. * @param clazz must not be {@literal null}. diff --git a/src/main/java/org/springframework/data/solr/core/SolrTemplate.java b/src/main/java/org/springframework/data/solr/core/SolrTemplate.java index 745b1dada..1452c665c 100644 --- a/src/main/java/org/springframework/data/solr/core/SolrTemplate.java +++ b/src/main/java/org/springframework/data/solr/core/SolrTemplate.java @@ -79,6 +79,7 @@ import org.springframework.data.solr.core.schema.SolrSchemaRequest; import org.springframework.data.solr.server.SolrClientFactory; import org.springframework.data.solr.server.support.HttpSolrClientFactory; +import org.springframework.data.solr.server.support.SolrClientUtils; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; @@ -89,8 +90,9 @@ * @author Joachim Uhrlass * @author Francisco Spaeth * @author Shiradwade Sateesh Krishna + * @author Venil Noronha */ -public class SolrTemplate implements SolrOperations, InitializingBean, ApplicationContextAware { +public class SolrTemplate implements SolrOperations, MulticoreSolrOperations, InitializingBean, ApplicationContextAware { private static final Logger LOGGER = LoggerFactory.getLogger(SolrTemplate.class); private static final PersistenceExceptionTranslator EXCEPTION_TRANSLATOR = new SolrExceptionTranslator(); @@ -162,9 +164,20 @@ public SolrTemplate(SolrClientFactory solrClientFactory, SolrConverter solrConve @Override public T execute(SolrCallback action) { Assert.notNull(action); + SolrClient solrClient = this.getSolrClient(); + return execute(solrClient, action); + } + + @Override + public T execute(String coreName, SolrCallback action) { + Assert.notNull(coreName); + Assert.notNull(action); + SolrClient solrClient = this.getSolrClient(coreName); + return execute(solrClient, action); + } + private T execute(SolrClient solrClient, SolrCallback action) { try { - SolrClient solrClient = this.getSolrClient(); return action.doInSolr(solrClient); } catch (Exception e) { DataAccessException resolved = getExceptionTranslator() @@ -175,7 +188,13 @@ public T execute(SolrCallback action) { @Override public SolrPingResponse ping() { - return execute(new SolrCallback() { + return ping(solrCore); + } + + @Override + public SolrPingResponse ping(String coreName) { + Assert.notNull(coreName, "Core name must not be 'null'."); + return execute(coreName, new SolrCallback() { @Override public SolrPingResponse doInSolr(SolrClient solrClient) throws SolrServerException, IOException { return solrClient.ping(); @@ -184,25 +203,31 @@ public SolrPingResponse doInSolr(SolrClient solrClient) throws SolrServerExcepti } @Override - public long count(final SolrDataQuery query) { + public long count(SolrDataQuery query) { return count(query, getDefaultRequestMethod()); } @Override - public long count(final SolrDataQuery query, final RequestMethod method) { + public long count(String coreName, SolrDataQuery query) { + return count(coreName, query, getDefaultRequestMethod()); + } + + @Override + public long count(SolrDataQuery query, RequestMethod method) { + return count(solrCore, query, method); + } + @Override + public long count(String coreName, final SolrDataQuery query, final RequestMethod method) { + Assert.notNull(coreName, "Core name must not be 'null'."); Assert.notNull(query, "Query must not be 'null'."); Assert.notNull(method, "Method must not be 'null'."); - - return execute(new SolrCallback() { - + return execute(coreName, new SolrCallback() { @Override public Long doInSolr(SolrClient solrClient) throws SolrServerException, IOException { - SolrQuery solrQuery = queryParsers.getForClass(query.getClass()).constructSolrQuery(query); solrQuery.setStart(0); solrQuery.setRows(0); - return solrClient.query(solrQuery, getSolrRequestMethod(method)).getResults().getNumFound(); } }); @@ -214,9 +239,21 @@ public UpdateResponse saveBean(Object obj) { } @Override - public UpdateResponse saveBean(final Object objectToAdd, final int commitWithinMs) { + public UpdateResponse saveBean(String coreName, Object obj) { + return saveBean(coreName, obj, -1); + } + + @Override + public UpdateResponse saveBean(Object objectToAdd, int commitWithinMs) { + String coreName = SolrClientUtils.resolveSolrCoreName(objectToAdd.getClass(), solrCore); + return saveBean(coreName, objectToAdd, commitWithinMs); + } + + @Override + public UpdateResponse saveBean(String coreName, final Object objectToAdd, final int commitWithinMs) { + Assert.notNull(coreName, "Core name must not be 'null'."); assertNoCollection(objectToAdd); - return execute(new SolrCallback() { + return execute(coreName, new SolrCallback() { @Override public UpdateResponse doInSolr(SolrClient solrClient) throws SolrServerException, IOException { return solrClient.add(convertBeanToSolrInputDocument(objectToAdd), commitWithinMs); @@ -230,8 +267,21 @@ public UpdateResponse saveBeans(Collection beans) { } @Override - public UpdateResponse saveBeans(final Collection beansToAdd, final int commitWithinMs) { - return execute(new SolrCallback() { + public UpdateResponse saveBeans(String coreName, Collection beans) { + return saveBeans(coreName, beans, -1); + } + + @Override + public UpdateResponse saveBeans(Collection beansToAdd, int commitWithinMs) { + Object oneBean = beansToAdd.iterator().next(); + String coreName = SolrClientUtils.resolveSolrCoreName(oneBean.getClass(), solrCore); + return saveBeans(coreName, beansToAdd, commitWithinMs); + } + + @Override + public UpdateResponse saveBeans(String coreName, final Collection beansToAdd, final int commitWithinMs) { + Assert.notNull(coreName, "Core name must not be 'null'."); + return execute(coreName, new SolrCallback() { @Override public UpdateResponse doInSolr(SolrClient solrClient) throws SolrServerException, IOException { return solrClient.add(convertBeansToSolrInputDocuments(beansToAdd), commitWithinMs); @@ -245,8 +295,19 @@ public UpdateResponse saveDocument(SolrInputDocument document) { } @Override - public UpdateResponse saveDocument(final SolrInputDocument documentToAdd, final int commitWithinMs) { - return execute(new SolrCallback() { + public UpdateResponse saveDocument(String coreName, SolrInputDocument document) { + return saveDocument(coreName, document, -1); + } + + @Override + public UpdateResponse saveDocument(SolrInputDocument documentToAdd, int commitWithinMs) { + return saveDocument(solrCore, documentToAdd, commitWithinMs); + } + + @Override + public UpdateResponse saveDocument(String coreName, final SolrInputDocument documentToAdd, final int commitWithinMs) { + Assert.notNull(coreName, "Core name must not be 'null'."); + return execute(coreName, new SolrCallback() { @Override public UpdateResponse doInSolr(SolrClient solrClient) throws SolrServerException, IOException { return solrClient.add(documentToAdd, commitWithinMs); @@ -260,8 +321,19 @@ public UpdateResponse saveDocuments(Collection documents) { } @Override - public UpdateResponse saveDocuments(final Collection documentsToAdd, final int commitWithinMs) { - return execute(new SolrCallback() { + public UpdateResponse saveDocuments(String coreName, Collection documents) { + return saveDocuments(coreName, documents, -1); + } + + @Override + public UpdateResponse saveDocuments(Collection documentsToAdd, int commitWithinMs) { + return saveDocuments(solrCore, documentsToAdd, commitWithinMs); + } + + @Override + public UpdateResponse saveDocuments(String coreName, final Collection documentsToAdd, final int commitWithinMs) { + Assert.notNull(coreName, "Core name must not be 'null'."); + return execute(coreName, new SolrCallback() { @Override public UpdateResponse doInSolr(SolrClient solrClient) throws SolrServerException, IOException { return solrClient.add(documentsToAdd, commitWithinMs); @@ -271,11 +343,15 @@ public UpdateResponse doInSolr(SolrClient solrClient) throws SolrServerException @Override public UpdateResponse delete(SolrDataQuery query) { - Assert.notNull(query, "Query must not be 'null'."); + return delete(solrCore, query); + } + @Override + public UpdateResponse delete(String coreName, SolrDataQuery query) { + Assert.notNull(coreName, "Core name must not be 'null'."); + Assert.notNull(query, "Query must not be 'null'."); final String queryString = this.queryParsers.getForClass(query.getClass()).getQueryString(query); - - return execute(new SolrCallback() { + return execute(coreName, new SolrCallback() { @Override public UpdateResponse doInSolr(SolrClient solrClient) throws SolrServerException, IOException { return solrClient.deleteByQuery(queryString); @@ -284,10 +360,15 @@ public UpdateResponse doInSolr(SolrClient solrClient) throws SolrServerException } @Override - public UpdateResponse deleteById(final String id) { - Assert.notNull(id, "Cannot delete 'null' id."); + public UpdateResponse deleteById(String id) { + return deleteById(solrCore, id); + } - return execute(new SolrCallback() { + @Override + public UpdateResponse deleteById(String coreName, final String id) { + Assert.notNull(coreName, "Core name must not be 'null'."); + Assert.notNull(id, "Cannot delete 'null' id."); + return execute(coreName, new SolrCallback() { @Override public UpdateResponse doInSolr(SolrClient solrClient) throws SolrServerException, IOException { return solrClient.deleteById(id); @@ -297,10 +378,15 @@ public UpdateResponse doInSolr(SolrClient solrClient) throws SolrServerException @Override public UpdateResponse deleteById(Collection ids) { - Assert.notNull(ids, "Cannot delete 'null' collection."); + return deleteById(solrCore, ids); + } + @Override + public UpdateResponse deleteById(String coreName, Collection ids) { + Assert.notNull(coreName, "Core name must not be 'null'."); + Assert.notNull(ids, "Cannot delete 'null' collection."); final List toBeDeleted = new ArrayList(ids); - return execute(new SolrCallback() { + return execute(coreName, new SolrCallback() { @Override public UpdateResponse doInSolr(SolrClient solrClient) throws SolrServerException, IOException { return solrClient.deleteById(toBeDeleted); @@ -313,14 +399,25 @@ public T queryForObject(Query query, Class clazz) { return queryForObject(query, clazz, getDefaultRequestMethod()); } + @Override + public T queryForObject(String coreName, Query query, Class clazz) { + return queryForObject(coreName, query, clazz, getDefaultRequestMethod()); + } + @Override public T queryForObject(Query query, Class clazz, RequestMethod method) { + String coreName = SolrClientUtils.resolveSolrCoreName(clazz, solrCore); + return queryForObject(coreName, query, clazz, method); + } + @Override + public T queryForObject(String coreName, Query query, Class clazz, RequestMethod method) { + Assert.notNull(coreName, "Core name must not be 'null'."); Assert.notNull(query, "Query must not be 'null'."); Assert.notNull(clazz, "Target class must not be 'null'."); query.setPageRequest(new PageRequest(0, 1)); - QueryResponse response = query(query, clazz, method); + QueryResponse response = query(coreName, query, clazz, method); if (response.getResults().size() > 0) { if (response.getResults().size() > 1) { @@ -331,11 +428,12 @@ public T queryForObject(Query query, Class clazz, RequestMethod method) { return null; } - private SolrResultPage doQueryForPage(Query query, Class clazz, RequestMethod requestMethod) { + private SolrResultPage doQueryForPage(String coreName, Query query, Class clazz, + RequestMethod requestMethod) { QueryResponse response = null; NamedObjectsQuery namedObjectsQuery = new NamedObjectsQuery(query); - response = query(namedObjectsQuery, clazz, requestMethod != null ? requestMethod : getDefaultRequestMethod()); + response = query(coreName, namedObjectsQuery, clazz, requestMethod != null ? requestMethod : getDefaultRequestMethod()); Map objectsName = namedObjectsQuery.getNamesAssociation(); return createSolrResultPage(query, clazz, response, objectsName); @@ -343,59 +441,77 @@ private SolrResultPage doQueryForPage(Query query, Class clazz, Reques @Override public ScoredPage queryForPage(Query query, Class clazz) { + return queryForPage(query, clazz, getDefaultRequestMethod()); + } - Assert.notNull(query, "Query must not be 'null'."); - Assert.notNull(clazz, "Target class must not be 'null'."); - - return doQueryForPage(query, clazz, getDefaultRequestMethod()); + @Override + public ScoredPage queryForPage(String coreName, Query query, Class clazz) { + return queryForPage(coreName, query, clazz, getDefaultRequestMethod()); } - /* - * (non-Javadoc) - * @see org.springframework.data.solr.core.SolrOperations#queryForPage(org.springframework.data.solr.core.query.Query, java.lang.Class, org.springframework.data.solr.core.RequestMethod) - */ @Override public ScoredPage queryForPage(Query query, Class clazz, RequestMethod method) { + String coreName = SolrClientUtils.resolveSolrCoreName(clazz, solrCore); + return queryForPage(coreName, query, clazz, method); + } + @Override + public ScoredPage queryForPage(String coreName, Query query, Class clazz, RequestMethod method) { + Assert.notNull(coreName, "Core name must not be 'null'."); Assert.notNull(query, "Query must not be 'null'."); Assert.notNull(clazz, "Target class must not be 'null'."); Assert.notNull(method, "Method class must not be 'null'."); - - return doQueryForPage(query, clazz, method); + return doQueryForPage(coreName, query, clazz, method); } @Override public GroupPage queryForGroupPage(Query query, Class clazz) { - return queryForGroupPage(query, clazz, RequestMethod.GET); + return queryForGroupPage(query, clazz, getDefaultRequestMethod()); + } + + @Override + public GroupPage queryForGroupPage(String coreName, Query query, Class clazz) { + return queryForGroupPage(coreName, query, clazz, getDefaultRequestMethod()); } @Override public GroupPage queryForGroupPage(Query query, Class clazz, RequestMethod method) { + String coreName = SolrClientUtils.resolveSolrCoreName(clazz, solrCore); + return queryForGroupPage(coreName, query, clazz, method); + } + @Override + public GroupPage queryForGroupPage(String coreName, Query query, Class clazz, RequestMethod method) { + Assert.notNull(coreName, "Core name must not be 'null'."); Assert.notNull(query, "Query must not be 'null'."); Assert.notNull(clazz, "Target class must not be 'null'."); Assert.notNull(method, "Method class must not be 'null'."); - - return doQueryForPage(query, clazz, method); + return doQueryForPage(coreName, query, clazz, method); } - /* - * (non-Javadoc) - * @see org.springframework.data.solr.core.SolrOperations#queryForStatsPage(org.springframework.data.solr.core.query.Query, java.lang.Class) - */ @Override public StatsPage queryForStatsPage(Query query, Class clazz) { return queryForStatsPage(query, clazz, getDefaultRequestMethod()); } + @Override + public StatsPage queryForStatsPage(String coreName, Query query, Class clazz) { + return queryForStatsPage(coreName, query, clazz, getDefaultRequestMethod()); + } + @Override public StatsPage queryForStatsPage(Query query, Class clazz, RequestMethod method) { + String coreName = SolrClientUtils.resolveSolrCoreName(clazz, solrCore); + return queryForStatsPage(coreName, query, clazz, method); + } + @Override + public StatsPage queryForStatsPage(String coreName, Query query, Class clazz, RequestMethod method) { + Assert.notNull(coreName, "Core name must not be 'null'."); Assert.notNull(query, "Query must not be 'null'."); Assert.notNull(clazz, "Target class must not be 'null'."); Assert.notNull(method, "Method class must not be 'null'."); - - return doQueryForPage(query, clazz, method); + return doQueryForPage(coreName, query, clazz, method); } @Override @@ -403,14 +519,25 @@ public FacetPage queryForFacetPage(FacetQuery query, Class clazz) { return queryForFacetPage(query, clazz, getDefaultRequestMethod()); } + @Override + public FacetPage queryForFacetPage(String coreName, FacetQuery query, Class clazz) { + return queryForFacetPage(coreName, query, clazz, getDefaultRequestMethod()); + } + @Override public FacetPage queryForFacetPage(FacetQuery query, Class clazz, RequestMethod method) { + String coreName = SolrClientUtils.resolveSolrCoreName(clazz, solrCore); + return queryForFacetPage(coreName, query, clazz, method); + } + @Override + public FacetPage queryForFacetPage(String coreName, FacetQuery query, Class clazz, RequestMethod method) { + Assert.notNull(coreName, "Core name must not be 'null'."); Assert.notNull(query, "Query must not be 'null'."); Assert.notNull(clazz, "Target class must not be 'null'."); NamedObjectsFacetQuery namedObjectsQuery = new NamedObjectsFacetQuery(query); - QueryResponse response = query(namedObjectsQuery, clazz, method); + QueryResponse response = query(coreName, namedObjectsQuery, clazz, method); Map objectsName = namedObjectsQuery.getNamesAssociation(); SolrResultPage page = createSolrResultPage(query, clazz, response, objectsName); @@ -428,14 +555,26 @@ public HighlightPage queryForHighlightPage(HighlightQuery query, Class return queryForHighlightPage(query, clazz, getDefaultRequestMethod()); } + @Override + public HighlightPage queryForHighlightPage(String coreName, HighlightQuery query, Class clazz) { + return queryForHighlightPage(coreName, query, clazz, getDefaultRequestMethod()); + } + @Override public HighlightPage queryForHighlightPage(HighlightQuery query, Class clazz, RequestMethod method) { + String coreName = SolrClientUtils.resolveSolrCoreName(clazz, solrCore); + return queryForHighlightPage(coreName, query, clazz, method); + } + @Override + public HighlightPage queryForHighlightPage(String coreName, HighlightQuery query, Class clazz, + RequestMethod method) { + Assert.notNull(coreName, "Core name must not be 'null'."); Assert.notNull(query, "Query must not be 'null'."); Assert.notNull(clazz, "Target class must not be 'null'."); NamedObjectsHighlightQuery namedObjectsQuery = new NamedObjectsHighlightQuery(query); - QueryResponse response = query(namedObjectsQuery, clazz, getDefaultRequestMethod()); + QueryResponse response = query(coreName, namedObjectsQuery, clazz, getDefaultRequestMethod()); Map objectsName = namedObjectsQuery.getNamesAssociation(); @@ -470,23 +609,38 @@ public TermsPage queryForTermsPage(TermsQuery query) { } @Override - public TermsPage queryForTermsPage(TermsQuery query, RequestMethod method) { - - Assert.notNull(query, "Query must not be 'null'."); + public TermsPage queryForTermsPage(String coreName, TermsQuery query) { + return queryForTermsPage(coreName, query, getDefaultRequestMethod()); + } - QueryResponse response = query(query, null, method); + @Override + public TermsPage queryForTermsPage(TermsQuery query, RequestMethod method) { + return queryForTermsPage(solrCore, query, method); + } + @Override + public TermsPage queryForTermsPage(String coreName, TermsQuery query, RequestMethod method) { + QueryResponse response = query(coreName, query, null, method); TermsResultPage page = new TermsResultPage(); page.addAllTerms(ResultHelper.convertTermsQueryResponseToTermsMap(response)); return page; } final QueryResponse query(SolrDataQuery query, Class clazz) { - return query(query, clazz, defaultRequestMethod); + return query(query, clazz, getDefaultRequestMethod()); } - final QueryResponse query(SolrDataQuery query, Class clazz, RequestMethod requestMethod) { + final QueryResponse query(String coreName, SolrDataQuery query, Class clazz) { + return query(coreName, query, clazz, getDefaultRequestMethod()); + } + final QueryResponse query(SolrDataQuery query, Class clazz, RequestMethod requestMethod) { + String coreName = SolrClientUtils.resolveSolrCoreName(clazz, solrCore); + return query(coreName, query, clazz, requestMethod); + } + + final QueryResponse query(String coreName, SolrDataQuery query, Class clazz, RequestMethod requestMethod) { + Assert.notNull(coreName, "Core name must not be 'null'."); Assert.notNull(query, "Query must not be 'null'"); Assert.notNull(requestMethod, "RequestMethod must not be 'null'"); @@ -499,14 +653,17 @@ final QueryResponse query(SolrDataQuery query, Class clazz, RequestMethod req } } - LOGGER.debug("Executing query '" + solrQuery + "' against solr."); - - return executeSolrQuery(solrQuery, getSolrRequestMethod(requestMethod)); + LOGGER.debug("Executing query '" + solrQuery + "' against {} solr core.", coreName); + return executeSolrQuery(coreName, solrQuery, getSolrRequestMethod(requestMethod)); } - final QueryResponse executeSolrQuery(final SolrQuery solrQuery, final SolrRequest.METHOD method) { - - return execute(new SolrCallback() { + final QueryResponse executeSolrQuery(SolrQuery solrQuery, SolrRequest.METHOD method) { + return executeSolrQuery(solrCore, solrQuery, method); + } + + final QueryResponse executeSolrQuery(final String coreName, final SolrQuery solrQuery, + final SolrRequest.METHOD method) { + return execute(coreName, new SolrCallback() { @Override public QueryResponse doInSolr(SolrClient solrServer) throws SolrServerException, IOException { return solrServer.query(solrQuery, method); @@ -516,7 +673,13 @@ public QueryResponse doInSolr(SolrClient solrServer) throws SolrServerException, @Override public void commit() { - execute(new SolrCallback() { + commit(solrCore); + } + + @Override + public void commit(String coreName) { + Assert.notNull(coreName, "Core name must not be 'null'."); + execute(coreName, new SolrCallback() { @Override public UpdateResponse doInSolr(SolrClient solrClient) throws SolrServerException, IOException { return solrClient.commit(); @@ -526,11 +689,17 @@ public UpdateResponse doInSolr(SolrClient solrClient) throws SolrServerException @Override public void softCommit() { + softCommit(solrCore); + } + + @Override + public void softCommit(String coreName) { + Assert.notNull(coreName, "Core name must not be 'null'."); if (VersionUtil.isSolr3XAvailable()) { throw new UnsupportedOperationException( "Soft commit is not available for solr version lower than 4.x - Please check your depdendencies."); } - execute(new SolrCallback() { + execute(coreName, new SolrCallback() { @Override public UpdateResponse doInSolr(SolrClient solrClient) throws SolrServerException, IOException { return solrClient.commit(true, true, true); @@ -540,7 +709,13 @@ public UpdateResponse doInSolr(SolrClient solrClient) throws SolrServerException @Override public void rollback() { - execute(new SolrCallback() { + rollback(solrCore); + } + + @Override + public void rollback(String coreName) { + Assert.notNull(coreName, "Core name must not be 'null'."); + execute(coreName, new SolrCallback() { @Override public UpdateResponse doInSolr(SolrClient solrClient) throws SolrServerException, IOException { return solrClient.rollback(); @@ -565,8 +740,8 @@ public SolrInputDocument convertBeanToSolrInputDocument(Object bean) { * @since 1.3 */ public String getSchemaName(String collectionName) { - return execute(new SolrCallback() { - + Assert.notNull(collectionName, "Collection name must not be 'null'."); + return execute(collectionName, new SolrCallback() { @Override public String doInSolr(SolrClient solrClient) throws SolrServerException, IOException { SolrJsonResponse response = SolrSchemaRequest.name().process(solrClient); @@ -578,19 +753,21 @@ public String doInSolr(SolrClient solrClient) throws SolrServerException, IOExce }); } - /* - * (non-Javadoc) - * @see org.springframework.data.solr.core.SolrOperations#queryForCursor(org.springframework.data.solr.core.query.Query, java.lang.Class) - */ - public Cursor queryForCursor(Query query, final Class clazz) { + public Cursor queryForCursor(Query query, Class clazz) { + String coreName = SolrClientUtils.resolveSolrCoreName(clazz, solrCore); + return queryForCursor(coreName, query, clazz); + } + @Override + public Cursor queryForCursor(final String coreName, Query query, final Class clazz) { + Assert.notNull(coreName, "Core name must not be 'null'."); return new DelegatingCursor(queryParsers.getForClass(query.getClass()).constructSolrQuery(query)) { @Override protected org.springframework.data.solr.core.query.result.DelegatingCursor.PartialResult doLoad( SolrQuery nativeQuery) { - QueryResponse response = executeSolrQuery(nativeQuery, getSolrRequestMethod(getDefaultRequestMethod())); + QueryResponse response = executeSolrQuery(coreName, nativeQuery, getSolrRequestMethod(getDefaultRequestMethod())); if (response == null) { return new PartialResult("", Collections. emptyList()); } @@ -602,28 +779,35 @@ protected org.springframework.data.solr.core.query.result.DelegatingCursor.Parti } @Override - public Collection getById(final Collection ids, final Class clazz) { + public Collection getById(Collection ids, Class clazz) { + String coreName = SolrClientUtils.resolveSolrCoreName(clazz, solrCore); + return getById(coreName, ids, clazz); + } + @Override + public Collection getById(String coreName, final Collection ids, final Class clazz) { + Assert.notNull(coreName, "Core name must not be 'null'."); if (CollectionUtils.isEmpty(ids)) { return Collections.emptyList(); } - - return execute(new SolrCallback>() { + return execute(coreName, new SolrCallback>() { @Override public Collection doInSolr(SolrClient solrClient) throws SolrServerException, IOException { - QueryResponse response = new SolrRealtimeGetRequest(ids).process(solrClient); return convertSolrDocumentListToBeans(response.getResults(), clazz); } - }); } @Override public T getById(Serializable id, Class clazz) { + String coreName = SolrClientUtils.resolveSolrCoreName(clazz, solrCore); + return getById(coreName, id, clazz); + } + @Override + public T getById(String coreName, Serializable id, Class clazz) { Assert.notNull(id, "Id must not be 'null'."); - Collection result = getById(Collections.singletonList(id), clazz); if (result.isEmpty()) { return null; @@ -676,6 +860,11 @@ public final SolrClient getSolrClient() { return solrClientFactory.getSolrClient(this.solrCore); } + @Override + public final SolrClient getSolrClient(String coreName) { + return solrClientFactory.getSolrClient(coreName); + } + @Override public SolrConverter getConverter() { return this.solrConverter; diff --git a/src/main/java/org/springframework/data/solr/server/support/SolrClientUtils.java b/src/main/java/org/springframework/data/solr/server/support/SolrClientUtils.java index 545f62c8d..5adb345a7 100644 --- a/src/main/java/org/springframework/data/solr/server/support/SolrClientUtils.java +++ b/src/main/java/org/springframework/data/solr/server/support/SolrClientUtils.java @@ -50,6 +50,7 @@ * {@link SolrClientUtils} replaces SolrServerUtils from version 1.x * * @author Christoph Strobl + * @author Venil Noronha * @since 2.0 */ public class SolrClientUtils { @@ -67,11 +68,27 @@ private SolrClientUtils() {} * @since 1.1 */ public static String resolveSolrCoreName(Class type) { - SolrDocument annotation = AnnotationUtils.findAnnotation(type, SolrDocument.class); - if (annotation != null && StringUtils.isNotBlank(annotation.solrCoreName())) { - return annotation.solrCoreName(); + return SolrClientUtils.resolveSolrCoreName(type, ""); + } + + /** + * Resolves solr core/collection name from the given type's {@link SolrDocument} annotation. + * If type is null or isn't annotated with {@link SolrDocument}, the default + * core name is returned. + * + * @param type the {@link Class} for which core name is to be resolved. + * @param defaultCoreName the default core name. + * @return default core name if type is null or isn't annotated + * with {@link SolrDocument}. + */ + public static String resolveSolrCoreName(Class type, String defaultCoreName) { + if (type != null) { + SolrDocument annotation = AnnotationUtils.findAnnotation(type, SolrDocument.class); + if (annotation != null && StringUtils.isNotBlank(annotation.solrCoreName())) { + return annotation.solrCoreName(); + } } - return ""; + return defaultCoreName; } public static T clone(T solrClient) { diff --git a/src/test/java/org/springframework/data/solr/core/SolrTemplateMulticoreTests.java b/src/test/java/org/springframework/data/solr/core/SolrTemplateMulticoreTests.java new file mode 100644 index 000000000..44c1ac657 --- /dev/null +++ b/src/test/java/org/springframework/data/solr/core/SolrTemplateMulticoreTests.java @@ -0,0 +1,160 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.solr.core; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; + +import org.apache.solr.client.solrj.SolrClient; +import org.apache.solr.client.solrj.SolrQuery; +import org.apache.solr.client.solrj.SolrRequest; +import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.response.FacetField; +import org.apache.solr.client.solrj.response.QueryResponse; +import org.apache.solr.client.solrj.response.SolrPingResponse; +import org.apache.solr.common.SolrDocumentList; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.data.solr.core.mapping.SolrDocument; +import org.springframework.data.solr.core.query.Criteria; +import org.springframework.data.solr.core.query.FacetOptions; +import org.springframework.data.solr.core.query.FacetQuery; +import org.springframework.data.solr.core.query.Field; +import org.springframework.data.solr.core.query.SimpleFacetQuery; +import org.springframework.data.solr.core.query.SimpleQuery; +import org.springframework.data.solr.core.query.result.FacetPage; +import org.springframework.data.solr.server.SolrClientFactory; + +/** + * + * @author Venil Noronha + */ +@RunWith(MockitoJUnitRunner.class) +public class SolrTemplateMulticoreTests { + + private SolrTemplate solrTemplate; + private @Mock SolrClient defaultSolrClient; + private @Mock SolrClient core1Client; + private @Mock SolrClient core2Client; + private @Mock SolrClientFactory solrClientFactory; + + @Before + public void setUp() { + Mockito.when(solrClientFactory.getSolrClient()).thenReturn(defaultSolrClient); + Mockito.when(solrClientFactory.getSolrClient("core1")).thenReturn(core1Client); + Mockito.when(solrClientFactory.getSolrClient("core2")).thenReturn(core2Client); + solrTemplate = new SolrTemplate(solrClientFactory); + solrTemplate.afterPropertiesSet(); + } + + @Test + public void testGetSolrClients() throws SolrServerException, IOException { + SolrClient client1 = solrClientFactory.getSolrClient("core1"); + SolrClient client2 = solrClientFactory.getSolrClient("core2"); + assertNotNull(client1); + assertNotNull(client2); + assertEquals(core1Client, client1); + assertEquals(core2Client, client2); + } + + @Test + public void testPingSpecificCores() throws SolrServerException, IOException { + Mockito.when(core1Client.ping()).thenReturn(new SolrPingResponse()); + Mockito.when(core2Client.ping()).thenReturn(new SolrPingResponse()); + SolrPingResponse pingResult1 = solrTemplate.ping("core1"); + SolrPingResponse pingResult2 = solrTemplate.ping("core2"); + assertNotNull(pingResult1); + assertNotNull(pingResult2); + Mockito.verify(core1Client, Mockito.times(1)).ping(); + Mockito.verify(core2Client, Mockito.times(1)).ping(); + } + + @Test + public void testCountQueries() throws SolrServerException, IOException { + ArgumentCaptor captor1 = ArgumentCaptor.forClass(SolrQuery.class); + ArgumentCaptor captor2 = ArgumentCaptor.forClass(SolrQuery.class); + + QueryResponse response1Mock = Mockito.mock(QueryResponse.class); + SolrDocumentList resultList1 = new SolrDocumentList(); + resultList1.setNumFound(10); + Mockito.when(response1Mock.getResults()).thenReturn(resultList1); + QueryResponse response2Mock = Mockito.mock(QueryResponse.class); + SolrDocumentList resultList2 = new SolrDocumentList(); + resultList2.setNumFound(10); + Mockito.when(response2Mock.getResults()).thenReturn(resultList2); + + Mockito.when(core1Client.query(Mockito.any(SolrQuery.class), Mockito.eq(SolrRequest.METHOD.GET))).thenReturn(response1Mock); + Mockito.when(core2Client.query(Mockito.any(SolrQuery.class), Mockito.eq(SolrRequest.METHOD.GET))).thenReturn(response2Mock); + + long result1 = solrTemplate.count("core1", new SimpleQuery(new Criteria("field_1").is("value1"))); + long result2 = solrTemplate.count("core2", new SimpleQuery(new Criteria("field_2").is("value2"))); + assertEquals(resultList1.getNumFound(), result1); + assertEquals(resultList2.getNumFound(), result2); + + Mockito.verify(core1Client, Mockito.times(1)).query(captor1.capture(), Mockito.eq(SolrRequest.METHOD.GET)); + Mockito.verify(core2Client, Mockito.times(1)).query(captor2.capture(), Mockito.eq(SolrRequest.METHOD.GET)); + } + + @Test + public void testMultipleSolrDocumentBasedQueryForFacetPage() throws SolrServerException, IOException { + ArgumentCaptor captor1 = ArgumentCaptor.forClass(SolrQuery.class); + ArgumentCaptor captor2 = ArgumentCaptor.forClass(SolrQuery.class); + + QueryResponse response1Mock = Mockito.mock(QueryResponse.class); + Mockito.when(response1Mock.getFacetFields()).thenReturn(Arrays.asList(new FacetField("field_1"))); + QueryResponse response2Mock = Mockito.mock(QueryResponse.class); + Mockito.when(response2Mock.getFacetFields()).thenReturn(Arrays.asList(new FacetField("field_2"))); + + Mockito.when(core1Client.query(Mockito.any(SolrQuery.class), Mockito.eq(SolrRequest.METHOD.GET))).thenReturn(response1Mock); + Mockito.when(core2Client.query(Mockito.any(SolrQuery.class), Mockito.eq(SolrRequest.METHOD.GET))).thenReturn(response2Mock); + + FacetQuery query1 = new SimpleFacetQuery(Criteria.where("field_1").isNotNull()); + query1.setFacetOptions(new FacetOptions("field_1")); + FacetQuery query2 = new SimpleFacetQuery(Criteria.where("field_2").isNotNull()); + query2.setFacetOptions(new FacetOptions("field_2")); + + FacetPage result1 = solrTemplate.queryForFacetPage(query1, Core1Document.class); + FacetPage result2 = solrTemplate.queryForFacetPage(query2, Core2Document.class); + Collection facetFields1 = result1.getFacetFields(); + Collection facetFields2 = result2.getFacetFields(); + + assertTrue(facetFields1.iterator().next().getName().equals("field_1")); + assertTrue(facetFields2.iterator().next().getName().equals("field_2")); + Mockito.verify(core1Client, Mockito.times(1)).query(captor1.capture(), Mockito.eq(SolrRequest.METHOD.GET)); + Mockito.verify(core2Client, Mockito.times(1)).query(captor2.capture(), Mockito.eq(SolrRequest.METHOD.GET)); + } + + @SolrDocument(solrCoreName = "core1") + public class Core1Document { + + } + + @SolrDocument(solrCoreName = "core2") + public class Core2Document { + + } + +} diff --git a/src/test/java/org/springframework/data/solr/server/support/SolrClientUtilTests.java b/src/test/java/org/springframework/data/solr/server/support/SolrClientUtilTests.java index 5a686cf68..4aa1112cd 100644 --- a/src/test/java/org/springframework/data/solr/server/support/SolrClientUtilTests.java +++ b/src/test/java/org/springframework/data/solr/server/support/SolrClientUtilTests.java @@ -47,6 +47,7 @@ /** * @author Christoph Strobl + * @author Venil Noronha */ public class SolrClientUtilTests { @@ -203,6 +204,21 @@ public void testResolveSolrCoreNameShouldReturnAnnotationValueWhenPresent() { Assert.assertThat(SolrClientUtils.resolveSolrCoreName(ClassWithSolrDocumentAnnotation.class), equalTo("core1")); } + @Test + public void testResolveDefaultSolrCoreName() { + Assert.assertEquals("default-core", SolrClientUtils.resolveSolrCoreName(ClassWithoutSolrDocumentAnnotation.class, "default-core")); + } + + @Test + public void testResolveDefaultSolrCoreNameWithEmptyAnnotation() { + Assert.assertEquals("default-core", SolrClientUtils.resolveSolrCoreName(ClassWithEmptySolrDocumentAnnotation.class, "default-core")); + } + + @Test + public void testResolveDefaultSolrCoreNameWithAnnotation() { + Assert.assertEquals("core1", SolrClientUtils.resolveSolrCoreName(ClassWithSolrDocumentAnnotation.class, "default-core")); + } + /** * @see DATASOLR-189 */