/*
* Hibernate Search, full-text search for your domain model
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.search.test.configuration;
import java.lang.annotation.ElementType;
import org.junit.Assert;
import org.apache.lucene.search.Query;
import org.hibernate.search.exception.SearchException;
import org.hibernate.search.annotations.ProvidedId;
import org.hibernate.search.backend.spi.Work;
import org.hibernate.search.backend.spi.WorkType;
import org.hibernate.search.cfg.SearchMapping;
import org.hibernate.search.query.dsl.QueryBuilder;
import org.hibernate.search.spi.SearchIntegratorBuilder;
import org.hibernate.search.spi.SearchIntegrator;
import org.hibernate.search.testsupport.setup.SearchConfigurationForTest;
import org.hibernate.search.testsupport.setup.TransactionContextForTest;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
/**
* By overriding {@link org.hibernate.search.cfg.spi.SearchConfiguration#isIdProvidedImplicit()}
* we allow to assume entities are annotated with ProvidedId.
*
* @author Sanne Grinovero (C) 2012 Red Hat Inc.
*/
public class ImplicitProvidedIdTest {
@Rule
public ExpectedException exceptions = ExpectedException.none();
@Test
public void exceptionThrownWhenNotEnabled() {
SearchMapping mapping = new SearchMapping();
mapping
.entity( Book.class ).indexed()
//Entity missing both @DocumentId and @ProvidedId:
.property( "title", ElementType.FIELD ).field()
.property( "text", ElementType.FIELD ).field()
;
SearchConfigurationForTest cfg = new SearchConfigurationForTest()
.setProgrammaticMapping( mapping )
.addClass( Book.class );
exceptions.expect( SearchException.class );
exceptions.expectMessage( "HSEARCH000177" );
storeBooksViaProvidedId( cfg, ProvidedId.defaultFieldName, false );
}
@Test
public void usingConfigurationTypeOverride() {
SearchMapping mapping = new SearchMapping();
mapping
.entity( Book.class ).indexed()
//Entity missing both @DocumentId and @ProvidedId:
.property( "title", ElementType.FIELD ).field()
.property( "text", ElementType.FIELD ).field()
;
SearchConfigurationForTest cfg = new SearchConfigurationForTest()
.setProgrammaticMapping( mapping )
.setIdProvidedImplicit( true )
.addClass( Book.class );
storeBooksViaProvidedId( cfg, ProvidedId.defaultFieldName, false );
}
@Test
public void usingProvidedIdAsOptionsOverride() {
SearchMapping mapping = new SearchMapping();
mapping
.entity( Book.class ).indexed()
.providedId().name( "myID" )
//Entity missing both @DocumentId and @ProvidedId:
.property( "title", ElementType.FIELD ).field()
.property( "text", ElementType.FIELD ).field()
;
SearchConfigurationForTest cfg = new SearchConfigurationForTest()
.setProgrammaticMapping( mapping )
.setIdProvidedImplicit( true )
.addClass( Book.class );
storeBooksViaProvidedId( cfg, "myID", false );
}
@Test
public void usingExplicitProvidedId() {
SearchMapping mapping = new SearchMapping();
mapping
.entity( Book.class ).indexed()
.providedId().name( "myID" )
//Entity missing both @DocumentId and @ProvidedId:
.property( "title", ElementType.FIELD ).field()
.property( "text", ElementType.FIELD ).field()
;
SearchConfigurationForTest cfg = new SearchConfigurationForTest()
.setProgrammaticMapping( mapping )
.setIdProvidedImplicit( false ) //DEFAULT
.addClass( Book.class );
storeBooksViaProvidedId( cfg, "myID", false );
}
@Test
public void usingDefaultSettings() {
SearchMapping mapping = new SearchMapping();
mapping
.entity( Book.class ).indexed()
.providedId().name( "myID" )
//Entity missing both @DocumentId and @ProvidedId:
.property( "title", ElementType.FIELD ).field()
.property( "text", ElementType.FIELD ).field()
;
SearchConfigurationForTest cfg = new SearchConfigurationForTest()
.setProgrammaticMapping( mapping )
//.setIdProvidedImplicit( false ) //Test it's the default
.addClass( Book.class );
storeBooksViaProvidedId( cfg, "myID", false );
}
@Test
public void documentIdNotOverriden() {
SearchMapping mapping = new SearchMapping();
mapping
.entity( Book.class ).indexed()
.property( "title", ElementType.FIELD ).documentId()
.property( "text", ElementType.FIELD ).field()
;
SearchConfigurationForTest cfg = new SearchConfigurationForTest()
.setProgrammaticMapping( mapping )
//.setIdProvidedImplicit( false ) //Test it's the default
.addClass( Book.class );
storeBooksViaProvidedId( cfg, "title", true );
}
/**
* @param cfg The SearchFactory configuration to be tested
* @param fieldName The expected name of the ID field
*/
private void storeBooksViaProvidedId(SearchConfigurationForTest cfg, String fieldName, boolean matchTitle) {
SearchIntegrator searchIntegrator = null;
try {
//Should fail right here when @ProvidedId is not enabled:
searchIntegrator = new SearchIntegratorBuilder().configuration( cfg ).buildSearchIntegrator();
Book book = new Book();
book.title = "Less is nice";
book.text = "When using Infinispan Query, users have to always remember to add @ProvidedId on their classes" +
" or a nasty exception will remind them. Can't we just assume it's always annotated?";
String isbn = "some entity-external id";
Work work = new Work( book, isbn, WorkType.ADD, false );
TransactionContextForTest tc = new TransactionContextForTest();
searchIntegrator.getWorker().performWork( work, tc );
tc.end();
QueryBuilder queryBuilder = searchIntegrator.buildQueryBuilder()
.forEntity( Book.class )
.get();
Query query = queryBuilder.keyword()
.onField( fieldName )
.ignoreAnalyzer()
.matching( matchTitle ? book.title : isbn )
.createQuery();
int queryResultSize = searchIntegrator.createHSQuery( query, Book.class )
.queryResultSize();
Assert.assertEquals( 1, queryResultSize );
}
finally {
if ( searchIntegrator != null ) {
searchIntegrator.close();
}
}
}
/**
* Test entity. We use programmatic configuration to test different annotation combinations.
*/
static class Book {
String title;
String text;
}
}