From ad24967b53e8fb93d71e3948255629c861967b05 Mon Sep 17 00:00:00 2001 From: Rizwan Idrees Date: Tue, 5 Feb 2013 12:58:33 +0000 Subject: [PATCH] added version support and upgraded the version of elasticsearch to 0.20.4 --- pom.xml | 2 +- .../elasticsearch/annotations/Version.java | 10 +++ .../core/ElasticsearchTemplate.java | 6 +- .../ElasticsearchPersistentEntity.java | 2 +- .../ElasticsearchPersistentProperty.java | 2 + .../SimpleElasticsearchPersistentEntity.java | 21 +++++ ...SimpleElasticsearchPersistentProperty.java | 8 +- .../elasticsearch/core/query/IndexQuery.java | 9 ++ .../ElasticsearchEntityInformation.java | 3 +- ...MappingElasticsearchEntityInformation.java | 23 +++++ .../SimpleElasticsearchRepository.java | 8 ++ .../data/elasticsearch/Author.java | 19 ++-- .../data/elasticsearch/Book.java | 7 +- .../data/elasticsearch/SampleEntity.java | 17 ++++ ...mpleElasticsearchPersistentEntityTest.java | 90 +++++++++++++++++++ .../repositories/RepositoryTest.java | 53 +++++------ 16 files changed, 233 insertions(+), 47 deletions(-) create mode 100644 src/main/java/org/springframework/data/elasticsearch/annotations/Version.java create mode 100644 src/test/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentEntityTest.java diff --git a/pom.xml b/pom.xml index bd1ae1c91..f52e39cf0 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 3.1.2.RELEASE 1.7.1 2.6 - 0.20.2 + 0.20.4 4.2.2 1.4.0.RELEASE 2.1 diff --git a/src/main/java/org/springframework/data/elasticsearch/annotations/Version.java b/src/main/java/org/springframework/data/elasticsearch/annotations/Version.java new file mode 100644 index 000000000..d31297d06 --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/annotations/Version.java @@ -0,0 +1,10 @@ +package org.springframework.data.elasticsearch.annotations; + + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +@Documented +public @interface Version { +} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java b/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java index 8f26ff48f..b1e41af75 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java @@ -216,8 +216,12 @@ public class ElasticsearchTemplate implements ElasticsearchOperations { private IndexRequestBuilder prepareIndex(IndexQuery query){ try { ElasticsearchPersistentEntity persistentEntity = getPersistentEntityFor(query.getObject().getClass()); - return client.prepareIndex(persistentEntity.getIndexName(), persistentEntity.getIndexType(), query.getId()) + IndexRequestBuilder indexRequestBuilder = client.prepareIndex(persistentEntity.getIndexName(), persistentEntity.getIndexType(), query.getId()) .setSource(objectMapper.writeValueAsString(query.getObject())); + if(query.getVersion() != null){ + indexRequestBuilder.setVersion(query.getVersion()); + } + return indexRequestBuilder; } catch (IOException e) { throw new ElasticsearchException("failed to index the document [id: " + query.getId() +"]",e); } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/mapping/ElasticsearchPersistentEntity.java b/src/main/java/org/springframework/data/elasticsearch/core/mapping/ElasticsearchPersistentEntity.java index 9bac38e2e..1bc7aaf80 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/mapping/ElasticsearchPersistentEntity.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/mapping/ElasticsearchPersistentEntity.java @@ -21,5 +21,5 @@ public interface ElasticsearchPersistentEntity extends PersistentEntity { INSTANCE; diff --git a/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentEntity.java b/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentEntity.java index 82d8c1820..5b96e51de 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentEntity.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentEntity.java @@ -22,6 +22,7 @@ import org.springframework.context.expression.BeanFactoryAccessor; import org.springframework.context.expression.BeanFactoryResolver; import org.springframework.data.elasticsearch.annotations.Document; import org.springframework.data.mapping.model.BasicPersistentEntity; +import org.springframework.data.mapping.model.MappingException; import org.springframework.data.util.TypeInformation; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.util.Assert; @@ -41,6 +42,7 @@ public class SimpleElasticsearchPersistentEntity extends BasicPersistentEntit private final StandardEvaluationContext context; private String indexName; private String indexType; + private ElasticsearchPersistentProperty versionProperty; public SimpleElasticsearchPersistentEntity(TypeInformation typeInformation) { super(typeInformation); @@ -70,4 +72,23 @@ public class SimpleElasticsearchPersistentEntity extends BasicPersistentEntit public String getIndexType() { return indexType; } + + @Override + public ElasticsearchPersistentProperty getVersionProperty() { + return this.versionProperty; + } + + @Override + public void addPersistentProperty(ElasticsearchPersistentProperty property) { + super.addPersistentProperty(property); + if(property.isVersionProperty()){ + if (this.versionProperty != null) { + throw new MappingException(String.format( + "Attempt to add version property %s but already have property %s registered " + + "as version. Check your mapping configuration!", property.getField(), versionProperty.getField())); + } + Assert.isTrue(property.getType() == Long.class, "Version property should be Long"); + this.versionProperty = property; + } + } } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentProperty.java b/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentProperty.java index 87073ee7a..65e3fc5b4 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentProperty.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentProperty.java @@ -15,6 +15,7 @@ */ package org.springframework.data.elasticsearch.core.mapping; +import org.springframework.data.elasticsearch.annotations.Version; import org.springframework.data.mapping.Association; import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty; @@ -55,7 +56,12 @@ public class SimpleElasticsearchPersistentProperty extends AnnotationBasedPersis return super.isIdProperty() || SUPPORTED_ID_PROPERTY_NAMES.contains(getFieldName()); } - @Override + @Override + public boolean isVersionProperty(){ + return field.isAnnotationPresent(Version.class); + } + + @Override protected Association createAssociation() { return null; } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/query/IndexQuery.java b/src/main/java/org/springframework/data/elasticsearch/core/query/IndexQuery.java index e6092366e..ca84865f1 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/query/IndexQuery.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/query/IndexQuery.java @@ -5,6 +5,7 @@ public class IndexQuery{ private String id; private Object object; + private Long version; public String getId() { return id; @@ -21,4 +22,12 @@ public class IndexQuery{ public void setObject(Object object) { this.object = object; } + + public Long getVersion() { + return version; + } + + public void setVersion(Long version) { + this.version = version; + } } diff --git a/src/main/java/org/springframework/data/elasticsearch/repository/support/ElasticsearchEntityInformation.java b/src/main/java/org/springframework/data/elasticsearch/repository/support/ElasticsearchEntityInformation.java index 5f8518b49..80a3e6b9a 100644 --- a/src/main/java/org/springframework/data/elasticsearch/repository/support/ElasticsearchEntityInformation.java +++ b/src/main/java/org/springframework/data/elasticsearch/repository/support/ElasticsearchEntityInformation.java @@ -28,5 +28,6 @@ public interface ElasticsearchEntityInformation exte String getIdAttribute(); String getIndexName(); String getType(); - + String getVersionAttribute(); + Long getVersion(T entity); } diff --git a/src/main/java/org/springframework/data/elasticsearch/repository/support/MappingElasticsearchEntityInformation.java b/src/main/java/org/springframework/data/elasticsearch/repository/support/MappingElasticsearchEntityInformation.java index 2fbaa7561..0f612a97f 100644 --- a/src/main/java/org/springframework/data/elasticsearch/repository/support/MappingElasticsearchEntityInformation.java +++ b/src/main/java/org/springframework/data/elasticsearch/repository/support/MappingElasticsearchEntityInformation.java @@ -15,6 +15,8 @@ */ package org.springframework.data.elasticsearch.repository.support; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty; import org.springframework.data.mapping.model.BeanWrapper; @@ -32,6 +34,7 @@ import java.io.Serializable; public class MappingElasticsearchEntityInformation extends AbstractEntityInformation implements ElasticsearchEntityInformation { + private static final Logger logger = LoggerFactory.getLogger(MappingElasticsearchEntityInformation.class); private final ElasticsearchPersistentEntity entityMetadata; private final String indexName; private final String type; @@ -79,4 +82,24 @@ public class MappingElasticsearchEntityInformation e public String getType() { return type != null? type : entityMetadata.getIndexType(); } + + @Override + public String getVersionAttribute() { + return entityMetadata.getVersionProperty().getFieldName(); + } + + @Override + public Long getVersion(T entity) { + ElasticsearchPersistentProperty versionProperty = entityMetadata.getIdProperty(); + try { + if(versionProperty != null){ + return (Long) BeanWrapper.create(entity, null).getProperty(versionProperty); + } + } catch (Exception e) { + logger.debug("failed to retrieve version", e); + } + return null; + } } + + diff --git a/src/main/java/org/springframework/data/elasticsearch/repository/support/SimpleElasticsearchRepository.java b/src/main/java/org/springframework/data/elasticsearch/repository/support/SimpleElasticsearchRepository.java index b3eb2a277..ebe84b9ab 100644 --- a/src/main/java/org/springframework/data/elasticsearch/repository/support/SimpleElasticsearchRepository.java +++ b/src/main/java/org/springframework/data/elasticsearch/repository/support/SimpleElasticsearchRepository.java @@ -212,6 +212,7 @@ public class SimpleElasticsearchRepository implements ElasticsearchRepository IndexQuery query = new IndexQuery(); query.setObject(entity); query.setId(extractIdFromBean(entity)); + query.setVersion(extractVersionFromBean(entity)); return query; } @@ -266,4 +267,11 @@ public class SimpleElasticsearchRepository implements ElasticsearchRepository return null; } + private Long extractVersionFromBean(T entity){ + if (entityInformation != null) { + return entityInformation.getVersion(entity); + } + return null; + } + } diff --git a/src/test/java/org/springframework/data/elasticsearch/Author.java b/src/test/java/org/springframework/data/elasticsearch/Author.java index fc3b66d70..28c267e9a 100644 --- a/src/test/java/org/springframework/data/elasticsearch/Author.java +++ b/src/test/java/org/springframework/data/elasticsearch/Author.java @@ -1,16 +1,9 @@ package org.springframework.data.elasticsearch; public class Author { - private String name; - private String id; - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } + private String id; + private String name; public String getId() { return id; @@ -19,4 +12,12 @@ public class Author { public void setId(String id) { this.id = id; } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } } diff --git a/src/test/java/org/springframework/data/elasticsearch/Book.java b/src/test/java/org/springframework/data/elasticsearch/Book.java index eb4b28716..9f2e6e1a2 100644 --- a/src/test/java/org/springframework/data/elasticsearch/Book.java +++ b/src/test/java/org/springframework/data/elasticsearch/Book.java @@ -4,9 +4,10 @@ import org.springframework.data.elasticsearch.annotations.Document; @Document(indexName = "book",type = "book") public class Book { - private String id; - private String name; - private Author author; + + private String id; + private String name; + private Author author; public String getId() { return id; diff --git a/src/test/java/org/springframework/data/elasticsearch/SampleEntity.java b/src/test/java/org/springframework/data/elasticsearch/SampleEntity.java index 1b8cdcce2..3a5565914 100644 --- a/src/test/java/org/springframework/data/elasticsearch/SampleEntity.java +++ b/src/test/java/org/springframework/data/elasticsearch/SampleEntity.java @@ -4,6 +4,7 @@ import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import org.springframework.data.annotation.Id; import org.springframework.data.elasticsearch.annotations.Document; +import org.springframework.data.elasticsearch.annotations.Version; @Document(indexName = "test-index", type = "test-type") public class SampleEntity { @@ -14,6 +15,8 @@ public class SampleEntity { private String message; private int rate; private boolean available; + @Version + private Long version; public String getId() { return id; @@ -55,6 +58,14 @@ public class SampleEntity { this.available = available; } + public Long getVersion() { + return version; + } + + public void setVersion(Long version) { + this.version = version; + } + @Override public boolean equals(Object obj) { if (!(obj instanceof SampleEntity)) { @@ -67,6 +78,9 @@ public class SampleEntity { return new EqualsBuilder().append(this.id, rhs.id) .append(this.type, rhs.type) .append(this.message, rhs.message) + .append(this.rate,rhs.rate) + .append(this.available,rhs.available) + .append(this.version,rhs.version) .isEquals(); } @@ -76,6 +90,9 @@ public class SampleEntity { .append(id) .append(type) .append(message) + .append(rate) + .append(available) + .append(version) .toHashCode(); } } diff --git a/src/test/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentEntityTest.java b/src/test/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentEntityTest.java new file mode 100644 index 000000000..a7dbd12a0 --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/core/mapping/SimpleElasticsearchPersistentEntityTest.java @@ -0,0 +1,90 @@ +package org.springframework.data.elasticsearch.core.mapping; + +import org.junit.Test; +import org.springframework.data.elasticsearch.annotations.Version; +import org.springframework.data.mapping.model.MappingException; +import org.springframework.data.mapping.model.SimpleTypeHolder; +import org.springframework.data.util.ClassTypeInformation; +import org.springframework.data.util.TypeInformation; + +import java.beans.IntrospectionException; +import java.beans.PropertyDescriptor; + +public class SimpleElasticsearchPersistentEntityTest { + + @Test(expected = IllegalArgumentException.class) + public void shouldThrowExceptionGivenVersionPropertyIsNotLong() throws NoSuchFieldException, IntrospectionException { + //given + TypeInformation typeInformation = ClassTypeInformation.from(EntityWithWrongVersionType.class); + SimpleElasticsearchPersistentProperty persistentProperty = + new SimpleElasticsearchPersistentProperty(EntityWithWrongVersionType.class.getDeclaredField("version"), + new PropertyDescriptor("version", EntityWithWrongVersionType.class), + new SimpleElasticsearchPersistentEntity(typeInformation), + new SimpleTypeHolder()); + + //when + new SimpleElasticsearchPersistentEntity(typeInformation).addPersistentProperty(persistentProperty); + } + + + @Test(expected = MappingException.class) + public void shouldThrowExceptionGivenMultipleVersionPropertiesArePresent() throws NoSuchFieldException, IntrospectionException { + //given + TypeInformation typeInformation = ClassTypeInformation.from(EntityWithMultipleVersionField.class); + SimpleElasticsearchPersistentProperty persistentProperty1 = + new SimpleElasticsearchPersistentProperty(EntityWithMultipleVersionField.class.getDeclaredField("version1"), + new PropertyDescriptor("version1", EntityWithMultipleVersionField.class), + new SimpleElasticsearchPersistentEntity(typeInformation), + new SimpleTypeHolder()); + + SimpleElasticsearchPersistentProperty persistentProperty2 = + new SimpleElasticsearchPersistentProperty(EntityWithMultipleVersionField.class.getDeclaredField("version2"), + new PropertyDescriptor("version2", EntityWithMultipleVersionField.class), + new SimpleElasticsearchPersistentEntity(typeInformation), + new SimpleTypeHolder()); + + SimpleElasticsearchPersistentEntity simpleElasticsearchPersistentEntity = new SimpleElasticsearchPersistentEntity(typeInformation); + simpleElasticsearchPersistentEntity.addPersistentProperty(persistentProperty1); + //when + simpleElasticsearchPersistentEntity.addPersistentProperty(persistentProperty2); + } + + + private class EntityWithWrongVersionType { + @Version + private String version; + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + } + + private class EntityWithMultipleVersionField{ + + @Version + private Long version1; + @Version + private Long version2; + + public Long getVersion1() { + return version1; + } + + public void setVersion1(Long version1) { + this.version1 = version1; + } + + public Long getVersion2() { + return version2; + } + + public void setVersion2(Long version2) { + this.version2 = version2; + } + } + +} diff --git a/src/test/java/org/springframework/data/elasticsearch/repositories/RepositoryTest.java b/src/test/java/org/springframework/data/elasticsearch/repositories/RepositoryTest.java index 097359e07..42d37e04c 100644 --- a/src/test/java/org/springframework/data/elasticsearch/repositories/RepositoryTest.java +++ b/src/test/java/org/springframework/data/elasticsearch/repositories/RepositoryTest.java @@ -27,7 +27,6 @@ public class RepositoryTest { @Resource private SampleElasticsearchRepository repository; - @Test public void shouldDoBulkIndexDocument(){ //given @@ -148,7 +147,7 @@ public class RepositoryTest { @Test @Ignore - public void testFindAllByIdQuery(){ + public void shouldFindAllByIdQuery(){ //todo : find solution for findAll(Iterable ids) //given String documentId = randomNumeric(5); @@ -171,31 +170,27 @@ public class RepositoryTest { } @Test - public void testSaveIterableEntities(){ - //given - + public void shouldSaveIterableEntities(){ + //given String documentId = randomNumeric(5); - SampleEntity sampleEntity = new SampleEntity(); - sampleEntity.setId(documentId); - sampleEntity.setMessage("hello world."); + SampleEntity sampleEntity1 = new SampleEntity(); + sampleEntity1.setId(documentId); + sampleEntity1.setMessage("hello world."); String documentId2 = randomNumeric(5); SampleEntity sampleEntity2 = new SampleEntity(); sampleEntity2.setId(documentId2); sampleEntity2.setMessage("hello world."); - - Iterable sampleEntities = Arrays.asList(sampleEntity,sampleEntity2); - + Iterable sampleEntities = Arrays.asList(sampleEntity1,sampleEntity2); //when repository.save(sampleEntities); - //then Page entities = repository.search(fieldQuery("id", documentId), new PageRequest(0, 50)); assertNotNull(entities); } @Test - public void testDocumentExistById(){ + public void shouldReturnTrueGivenDocumentWithIdExists(){ //given String documentId = randomNumeric(5); SampleEntity sampleEntity = new SampleEntity(); @@ -211,7 +206,7 @@ public class RepositoryTest { } @Test - public void testSearchForGivenSearchQuery(){ + public void shouldReturnResultsForGivenSearchQuery(){ //given String documentId = randomNumeric(5); SampleEntity sampleEntity = new SampleEntity(); @@ -227,7 +222,7 @@ public class RepositoryTest { } @Test - public void testDeleteAll(){ + public void shouldDeleteAll(){ //when repository.deleteAll(); //then @@ -238,7 +233,7 @@ public class RepositoryTest { } @Test - public void testDeleteByEntity(){ + public void shouldDeleteEntity(){ //given String documentId = randomNumeric(5); SampleEntity sampleEntity = new SampleEntity(); @@ -255,28 +250,30 @@ public class RepositoryTest { } @Test - public void testSearchForReturnIterableEntities(){ + public void shouldReturnIterableEntities(){ //given String documentId = randomNumeric(5); - SampleEntity sampleEntity = new SampleEntity(); - sampleEntity.setId(documentId); - sampleEntity.setMessage("hello world."); - repository.save(sampleEntity); + SampleEntity sampleEntity1 = new SampleEntity(); + sampleEntity1.setId(documentId); + sampleEntity1.setMessage("hello world."); + sampleEntity1.setVersion(System.currentTimeMillis()); + repository.save(sampleEntity1); String documentId2 = randomNumeric(5); SampleEntity sampleEntity2 = new SampleEntity(); sampleEntity2.setId(documentId2); sampleEntity2.setMessage("hello world."); + sampleEntity2.setVersion(System.currentTimeMillis()); repository.save(sampleEntity2); //when Iterable sampleEntities=repository.search(fieldQuery("id",documentId)); - //then + //then assertNotNull("sample entities cant be null..", sampleEntities); } @Test - public void testDeleteIterableEntities(){ + public void shouldDeleteIterableEntities(){ //given String documentId = randomNumeric(5); SampleEntity sampleEntity = new SampleEntity(); @@ -291,10 +288,8 @@ public class RepositoryTest { repository.save(sampleEntity); Iterable sampleEntities = Arrays.asList(sampleEntity,sampleEntity2); - //when repository.delete(sampleEntities); - //then Page entities = repository.search(fieldQuery("id", documentId), new PageRequest(0,50)); assertThat(entities.getTotalElements(),equalTo(0L)); @@ -303,11 +298,12 @@ public class RepositoryTest { } @Test - public void testIndexEntity(){ + public void shouldIndexEntity(){ //given String documentId = randomNumeric(5); SampleEntity sampleEntity = new SampleEntity(); sampleEntity.setId(documentId); + sampleEntity.setVersion(System.currentTimeMillis()); sampleEntity.setMessage("some message"); //when repository.index(sampleEntity); @@ -318,7 +314,7 @@ public class RepositoryTest { @Test @Ignore("By default, the search request will fail if there is no mapping associated with a field. The ignore_unmapped option allows to ignore fields that have no mapping and not sort by them") - public void testFindBySort(){ + public void shouldSortByGivenField(){ //todo //given String documentId = randomNumeric(5); @@ -332,12 +328,9 @@ public class RepositoryTest { sampleEntity2.setId(documentId2); sampleEntity2.setMessage("B.hello world."); repository.save(sampleEntity2); - //when Iterable sampleEntities=repository.findAll(new Sort(new Sort.Order(Sort.Direction.ASC,"message"))); - //then assertThat(sampleEntities,is(notNullValue())); } - }