diff --git a/pom.xml b/pom.xml index db38bc55..fe318585 100644 --- a/pom.xml +++ b/pom.xml @@ -16,11 +16,12 @@ - multi-store jpa mongodb + multi-store rest redis + solr @@ -76,4 +77,4 @@ - \ No newline at end of file + diff --git a/solr/example/Readme.md b/solr/example/Readme.md new file mode 100644 index 00000000..1682ca7c --- /dev/null +++ b/solr/example/Readme.md @@ -0,0 +1,11 @@ +# Spring Data Solr - Examples + +In order to run this example a 4.7+ [Solr Server](http://lucene.apache.org/solr/downloads.html) and [Maven](http://maven.apache.org/download.cgi) are required. + +### Running Solr +```emacs +:solr> cd example +:example> java -jar start.jar +``` + +Access via [localhost:8983/solr/](http://localhost:8983/solr/#/collection1) diff --git a/solr/example/pom.xml b/solr/example/pom.xml new file mode 100644 index 00000000..be861407 --- /dev/null +++ b/solr/example/pom.xml @@ -0,0 +1,23 @@ + + 4.0.0 + + + org.springframework.data.examples + spring-data-solr-examples + 1.0.0.BUILD-SNAPSHOT + + + spring-data-solr-example + Spring Data Solr - Example + + + + ${project.groupId} + spring-data-solr-example-utils + ${project.version} + test + + + + \ No newline at end of file diff --git a/solr/example/src/main/java/example/springdata/solr/Product.java b/solr/example/src/main/java/example/springdata/solr/Product.java new file mode 100644 index 00000000..bdebed2e --- /dev/null +++ b/solr/example/src/main/java/example/springdata/solr/Product.java @@ -0,0 +1,48 @@ +/* + * Copyright 2014 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 example.springdata.solr; + +import java.util.List; + +import lombok.Data; + +import org.springframework.data.annotation.Id; +import org.springframework.data.geo.Point; +import org.springframework.data.solr.core.mapping.Indexed; +import org.springframework.data.solr.core.mapping.SolrDocument; + +/** + * Document representing a Product and its attributes matching the fieldes defined in the example solr schema. + * + * @author Christoph Strobl + */ +@Data +@SolrDocument(solrCoreName = "collection1") +public class Product { + + private @Id String id; + private @Indexed String name; + private @Indexed(name = "cat") List category; + private @Indexed(name = "store") Point location; + private @Indexed boolean inStock; + + @Override + public String toString() { + return "Product [id=" + id + ", name=" + name + ", category=" + category + ", location=" + location + ", inStock=" + + inStock + "]"; + } +} diff --git a/solr/example/src/main/java/example/springdata/solr/ProductRepository.java b/solr/example/src/main/java/example/springdata/solr/ProductRepository.java new file mode 100644 index 00000000..b5e9b46e --- /dev/null +++ b/solr/example/src/main/java/example/springdata/solr/ProductRepository.java @@ -0,0 +1,27 @@ +/* + * Copyright 2014 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 example.springdata.solr; + +import org.springframework.data.repository.CrudRepository; + +/** + * Repository definition for {@link Product}. + * + * @author Christoph Strobl + */ +public interface ProductRepository extends ProductRepositoryCustom, CrudRepository { + +} diff --git a/solr/example/src/main/java/example/springdata/solr/ProductRepositoryCustom.java b/solr/example/src/main/java/example/springdata/solr/ProductRepositoryCustom.java new file mode 100644 index 00000000..0a686993 --- /dev/null +++ b/solr/example/src/main/java/example/springdata/solr/ProductRepositoryCustom.java @@ -0,0 +1,29 @@ +/* + * Copyright 2014 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 example.springdata.solr; + +import org.springframework.data.repository.Repository; +import org.springframework.data.solr.core.query.result.Cursor; + +/** + * Custom repository implementation to show special solr functions without {@link Repository} abstraction. + * + * @author Christoph Strobl + */ +public interface ProductRepositoryCustom { + + Cursor findAllUsingCursor(); +} diff --git a/solr/example/src/main/java/example/springdata/solr/ProductRepositoryImpl.java b/solr/example/src/main/java/example/springdata/solr/ProductRepositoryImpl.java new file mode 100644 index 00000000..ed2da7de --- /dev/null +++ b/solr/example/src/main/java/example/springdata/solr/ProductRepositoryImpl.java @@ -0,0 +1,43 @@ +/* + * Copyright 2014 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 example.springdata.solr; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Sort; +import org.springframework.data.solr.core.SolrTemplate; +import org.springframework.data.solr.core.query.SimpleQuery; +import org.springframework.data.solr.core.query.result.Cursor; + +/** + * Implementation of {@link ProductRepositoryCustom}. + * + * @author Christoph Strobl + */ +public class ProductRepositoryImpl implements ProductRepositoryCustom { + + @Autowired SolrTemplate solrTemplate; + + /* + * (non-Javadoc) + * @see example.springdata.solr.ProductRepositoryCustom#findAllUsingCursor() + */ + @Override + public Cursor findAllUsingCursor() { + + // NOTE: Using Cursor requires to sort by an unique field + return solrTemplate.queryForCursor(new SimpleQuery("*:*").addSort(new Sort("id")), Product.class); + } +} diff --git a/solr/example/src/test/java/example/springdata/solr/SolrRepositoryTests.java b/solr/example/src/test/java/example/springdata/solr/SolrRepositoryTests.java new file mode 100644 index 00000000..973ef3de --- /dev/null +++ b/solr/example/src/test/java/example/springdata/solr/SolrRepositoryTests.java @@ -0,0 +1,67 @@ +/* + * Copyright 2014 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 example.springdata.solr; + +import java.util.Iterator; + +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.solr.core.query.result.Cursor; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import example.springdata.solr.test.util.RequiresSolrServer; + +/** + * @author Christoph Strobl + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = { SolrTestConfiguration.class }) +public class SolrRepositoryTests { + + public static @ClassRule RequiresSolrServer requiresRunningServer = RequiresSolrServer.onLocalhost(); + + @Autowired ProductRepository repo; + + /** + * Finds all entries using a single request. + */ + @Test + public void findAll() { + + Iterator iterator = repo.findAll().iterator(); + printResult(iterator); + } + + /** + * Pages through all entries using cursor marks. Have a look at the Solr console output to see iteration steps. + */ + @Test + public void findAllUsingDeepPagination() { + + Cursor cursor = repo.findAllUsingCursor(); + printResult(cursor); + } + + private void printResult(Iterator it) { + + while (it.hasNext()) { + System.out.println(it.next()); + } + } +} diff --git a/solr/example/src/test/java/example/springdata/solr/SolrTestConfiguration.java b/solr/example/src/test/java/example/springdata/solr/SolrTestConfiguration.java new file mode 100644 index 00000000..0fc56886 --- /dev/null +++ b/solr/example/src/test/java/example/springdata/solr/SolrTestConfiguration.java @@ -0,0 +1,66 @@ +/* + * Copyright 2014 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 example.springdata.solr; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +import org.apache.solr.client.solrj.impl.HttpSolrServer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.solr.core.SolrTemplate; + +/** + * @author Christoph Strobl + */ +@Configuration +@EnableAutoConfiguration +public class SolrTestConfiguration { + + @Autowired CrudRepository repo; + + @Bean + public SolrTemplate solrTemplate() { + return new SolrTemplate(new HttpSolrServer("http://localhost:8983/solr"), "collection1"); + } + + /** + * Remove test data when context is shut down. + */ + @PreDestroy + public void deleteDocumentsOnShutdown() { + repo.deleteAll(); + } + + /** + * Initialize Solr instance with test data once context has started. + */ + @PostConstruct + public void initWithTestData() { + + for (int i = 0; i < 100; i++) { + + Product p = new Product(); + p.setId("p-" + i); + p.setName("foobar"); + + repo.save(p); + } + } +} diff --git a/solr/example/src/test/resources/logback.xml b/solr/example/src/test/resources/logback.xml new file mode 100644 index 00000000..a8128ca5 --- /dev/null +++ b/solr/example/src/test/resources/logback.xml @@ -0,0 +1,16 @@ + + + + + + %d %5p %40.40c:%4L - %m%n + + + + + + + + + + \ No newline at end of file diff --git a/solr/managed-schema/Readme.md b/solr/managed-schema/Readme.md new file mode 100644 index 00000000..a2774c42 --- /dev/null +++ b/solr/managed-schema/Readme.md @@ -0,0 +1,12 @@ +# Spring Data Solr - Managed Schema Examples + +In order to run this example a 4.7+ [Solr Server](http://lucene.apache.org/solr/downloads.html) and [Maven](http://maven.apache.org/download.cgi) are required. + +### Running Solr +```emacs +:solr> cd example +:example> java -Dsolr.solr.home=example-schemaless/solr -jar start.jar +``` + +Access via [localhost:8983/solr/](http://localhost:8983/solr/#/collection1). +Fields available at [../schema/fields](http://localhost:8983/solr/collection1/schema/fields) \ No newline at end of file diff --git a/solr/managed-schema/pom.xml b/solr/managed-schema/pom.xml new file mode 100644 index 00000000..638e7081 --- /dev/null +++ b/solr/managed-schema/pom.xml @@ -0,0 +1,23 @@ + + 4.0.0 + + + org.springframework.data.examples + spring-data-solr-examples + 1.0.0.BUILD-SNAPSHOT + + + spring-data-solr-managed-schema-example + Spring Data Solr - Managed schema examples + + + + ${project.groupId} + spring-data-solr-example-utils + ${project.version} + test + + + + \ No newline at end of file diff --git a/solr/managed-schema/src/main/java/example/springdata/solr/ManagedProduct.java b/solr/managed-schema/src/main/java/example/springdata/solr/ManagedProduct.java new file mode 100644 index 00000000..54982f1a --- /dev/null +++ b/solr/managed-schema/src/main/java/example/springdata/solr/ManagedProduct.java @@ -0,0 +1,44 @@ +/* + * Copyright 2014 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 example.springdata.solr; + +import java.util.List; + +import lombok.Data; + +import org.springframework.data.annotation.Id; +import org.springframework.data.solr.core.mapping.Indexed; +import org.springframework.data.solr.core.mapping.SolrDocument; + +/** + * Document representing a Product and its attributes that are propagated to the solr schema on first save of entity. + * + * @author Christoph Strobl + */ +@SolrDocument(solrCoreName = "collection1") +@Data +public class ManagedProduct { + + private @Id String id; + private @Indexed(type = "text_general") String name; + private @Indexed(name = "cat", type = "string") List category; + private @Indexed boolean inStock; + + @Override + public String toString() { + return "Product [id=" + id + ", name=" + name + ", category=" + category + ", inStock=" + inStock + "]"; + } +} diff --git a/solr/managed-schema/src/main/java/example/springdata/solr/ProductRepository.java b/solr/managed-schema/src/main/java/example/springdata/solr/ProductRepository.java new file mode 100644 index 00000000..3c74792a --- /dev/null +++ b/solr/managed-schema/src/main/java/example/springdata/solr/ProductRepository.java @@ -0,0 +1,27 @@ +/* + * Copyright 2014 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 example.springdata.solr; + +import org.springframework.data.repository.CrudRepository; + +/** + * Repository definition for {@link ManagedProduct}. + * + * @author Christoph Strobl + */ +public interface ProductRepository extends CrudRepository { + +} diff --git a/solr/managed-schema/src/test/java/example/springdata/solr/SolrRepositoryTests.java b/solr/managed-schema/src/test/java/example/springdata/solr/SolrRepositoryTests.java new file mode 100644 index 00000000..68fe1d2a --- /dev/null +++ b/solr/managed-schema/src/test/java/example/springdata/solr/SolrRepositoryTests.java @@ -0,0 +1,58 @@ +/* + * Copyright 2014 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 example.springdata.solr; + +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import example.springdata.solr.test.util.RequiresSolrServer; + +/** + * @author Christoph Strobl + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = { SolrTestConfiguration.class }) +public class SolrRepositoryTests { + + public static @ClassRule RequiresSolrServer requiresRunningServer = RequiresSolrServer.onLocalhost(); + + @Autowired ProductRepository repo; + + /** + * Adds missing fields to the schema.
+ * By default the fields {@literal id} and {@literal _version_} are present.
+ * Check fields using ../solr/collection1/schema/fields
+ *
+ * NOTE: requires Solr to run in managed schema mode. + */ + @Test + public void triggerSchemaUpdateOnFirstSave() { + + ManagedProduct p = new ManagedProduct(); + p.setId("p-1"); + repo.save(p); + + Iterable all = repo.findAll(); + for (ManagedProduct product : all) { + System.out.println(product); + } + } +} diff --git a/solr/managed-schema/src/test/java/example/springdata/solr/SolrTestConfiguration.java b/solr/managed-schema/src/test/java/example/springdata/solr/SolrTestConfiguration.java new file mode 100644 index 00000000..2df8d7c7 --- /dev/null +++ b/solr/managed-schema/src/test/java/example/springdata/solr/SolrTestConfiguration.java @@ -0,0 +1,53 @@ +/* + * Copyright 2014 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 example.springdata.solr; + +import javax.annotation.PreDestroy; + +import org.apache.solr.client.solrj.SolrServer; +import org.apache.solr.client.solrj.impl.HttpSolrServer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.solr.repository.config.EnableSolrRepositories; + +/** + * {@link Configuration} class enabling schema support for solr.
+ *
+ * NOTE: Requires solr to run in managed schema mode. run with + * {@code solr/example $ java -Dsolr.solr.home=example-schemaless/solr -jar start.jar}. + * + * @author Christoph Strobl + */ +@Configuration +@EnableSolrRepositories(schemaCreationSupport = true, multicoreSupport = true) +public class SolrTestConfiguration { + + @Autowired ProductRepository repo; + + @Bean + public SolrServer solrServer() { + return new HttpSolrServer("http://localhost:8983/solr"); + } + + /** + * Remove test data when context is shut down. + */ + @PreDestroy + public void deleteDocumentsOnShutdown() { + repo.deleteAll(); + } +} diff --git a/solr/managed-schema/src/test/resources/logback.xml b/solr/managed-schema/src/test/resources/logback.xml new file mode 100644 index 00000000..65fefdd2 --- /dev/null +++ b/solr/managed-schema/src/test/resources/logback.xml @@ -0,0 +1,16 @@ + + + + + + %d %5p %40.40c:%4L - %m%n + + + + + + + + + + \ No newline at end of file diff --git a/solr/pom.xml b/solr/pom.xml new file mode 100644 index 00000000..43b56c9f --- /dev/null +++ b/solr/pom.xml @@ -0,0 +1,38 @@ + + 4.0.0 + + spring-data-solr-examples + pom + + + org.springframework.data.examples + spring-data-examples + 1.0.0.BUILD-SNAPSHOT + + + Spring Data Solr - Examples + Sample projects for Spring Data Solr + http://projects.spring.io/spring-data-solr + + + util + example + managed-schema + + + + + + org.springframework.boot + spring-boot-starter-data-solr + + + + joda-time + joda-time + + + + + \ No newline at end of file diff --git a/solr/util/pom.xml b/solr/util/pom.xml new file mode 100644 index 00000000..018d4825 --- /dev/null +++ b/solr/util/pom.xml @@ -0,0 +1,20 @@ + + 4.0.0 + + + org.springframework.data.examples + spring-data-solr-examples + 1.0.0.BUILD-SNAPSHOT + + + spring-data-solr-example-utils + Spring Data Solr - Example utilities + + + + junit + junit + + + \ No newline at end of file diff --git a/solr/util/src/main/java/example/springdata/solr/test/util/RequiresSolrServer.java b/solr/util/src/main/java/example/springdata/solr/test/util/RequiresSolrServer.java new file mode 100644 index 00000000..7eccbd1a --- /dev/null +++ b/solr/util/src/main/java/example/springdata/solr/test/util/RequiresSolrServer.java @@ -0,0 +1,76 @@ +/* + * Copyright 2014 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 example.springdata.solr.test.util; + +import java.io.IOException; + +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.hamcrest.core.Is; +import org.junit.Assume; +import org.junit.internal.AssumptionViolatedException; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +/** + * {@link TestRule} implementation using {@link CloseableHttpClient} to check if Solr is running by sending + * {@literal GET} request to {@literal /admin/ping}. + * + * @author Christoph Strobl + */ +public class RequiresSolrServer implements TestRule { + + private static final String PING_PATH = "/admin/ping"; + + private final String baseUrl; + + private RequiresSolrServer(String baseUrl) { + this.baseUrl = baseUrl; + } + + public static RequiresSolrServer onLocalhost() { + return new RequiresSolrServer("http://localhost:8983/solr"); + } + + @Override + public Statement apply(Statement base, Description description) { + return new Statement() { + + @Override + public void evaluate() throws Throwable { + + checkServerRunning(); + base.evaluate(); + } + }; + } + + private void checkServerRunning() { + + try (CloseableHttpClient client = HttpClientBuilder.create().build()) { + CloseableHttpResponse response = client.execute(new HttpGet(baseUrl + PING_PATH)); + if (response != null && response.getStatusLine() != null) { + Assume.assumeThat(response.getStatusLine().getStatusCode(), Is.is(200)); + } + } catch (IOException e) { + throw new AssumptionViolatedException("SolrServer does not seem to be running", e); + } + } + +}