/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010, Red Hat, Inc. and/or its affiliates or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat, Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.search.test.embedded.depth;
import java.io.Serializable;
import java.util.List;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.search.annotations.IndexedEmbedded;
import org.hibernate.search.backend.LuceneWork;
import org.hibernate.search.FullTextQuery;
import org.hibernate.search.FullTextSession;
import org.hibernate.search.Search;
import org.hibernate.search.test.SearchTestCase;
import org.hibernate.search.test.util.LeakingLuceneBackend;
/**
* Verify the engine respects the depth parameter {@link IndexedEmbedded#depth()} without indexing larger graphs than
* requested.
* See the Genealogy graph at http://en.wikipedia.org/wiki/John,_King_of_England to visualize the data
* used as test case.
*
* @author Sanne Grinovero
*/
public class RecursiveGraphTest extends SearchTestCase {
public void testCorrectDepthIndexed() {
prepareGenealogyTree();
verifyMatchExistsWithName( 1L, "name", "John of England" );
verifyNoMatchExists( "parents.name", "John of England" );
verifyMatchExistsWithName( 1L, "parents.name", "Henry II of England" );
verifyMatchExistsWithName( 1L, "parents.parents.name", "Geoffrey V of Anjou" );
verifyMatchExistsWithName( 2L, "parents.parents.name", "Fulk V of Anjou" );
verifyNoMatchExists( "parents.parents.parents.name", "Fulk V of Anjou" );
LeakingLuceneBackend.reset();
renamePerson( 1L, "John Lackland" );
assertEquals( 1, countWorksDoneOnPerson( 1L ) );
assertEquals( 0, countWorksDoneOnPerson( 2L ) );
LeakingLuceneBackend.reset();
renamePerson( 2L, "Henry II of New England" );
assertEquals( 1, countWorksDoneOnPerson( 1L ) );
assertEquals( 1, countWorksDoneOnPerson( 2L ) );
LeakingLuceneBackend.reset();
renamePerson( 16L, "Fulk 4th of Anjou" );
assertEquals( 1, countWorksDoneOnPerson( 16L ) );
assertEquals( 0, countWorksDoneOnPerson( 17L ) );
assertEquals( 1, countWorksDoneOnPerson( 8L ) );
assertEquals( 1, countWorksDoneOnPerson( 4L ) );
assertEquals( 0, countWorksDoneOnPerson( 2L ) );
assertEquals( 0, countWorksDoneOnPerson( 1L ) );
}
/**
* rename a person having id to a new name
*/
private void renamePerson(Long id, String newName) {
FullTextSession fullTextSession = Search.getFullTextSession( openSession() );
try {
Transaction transaction = fullTextSession.beginTransaction();
Person kingJohn = (Person) fullTextSession.load( Person.class, id );
kingJohn.setName( newName );
transaction.commit();
}
finally {
fullTextSession.close();
}
}
/**
* asserts no results are returned for fieldName having fieldValue
*/
void verifyNoMatchExists(String fieldName, String fieldValue) {
FullTextSession fullTextSession = Search.getFullTextSession( openSession() );
try {
Transaction transaction = fullTextSession.beginTransaction();
Query q = new TermQuery( new Term( fieldName, fieldValue ) );
FullTextQuery fullTextQuery = fullTextSession.createFullTextQuery( q );
int resultSize = fullTextQuery.getResultSize();
assertEquals( 0, resultSize );
List<Person> list = fullTextQuery.list();
assertEquals( 0, list.size() );
transaction.commit();
}
finally {
fullTextSession.close();
}
}
void verifyMatchExistsWithName(Long expectedId, String fieldName, String fieldValue) {
FullTextSession fullTextSession = Search.getFullTextSession( openSession() );
try {
Transaction transaction = fullTextSession.beginTransaction();
Query q = new TermQuery( new Term( fieldName, fieldValue ) );
FullTextQuery fullTextQuery = fullTextSession.createFullTextQuery( q );
int resultSize = fullTextQuery.getResultSize();
assertEquals( 1, resultSize );
List<Person> list = fullTextQuery.list();
assertEquals( 1, list.size() );
assertEquals( expectedId, list.get( 0 ).getId() );
transaction.commit();
}
finally {
fullTextSession.close();
}
}
void prepareGenealogyTree() {
Session session = openSession();
Transaction transaction = session.beginTransaction();
Person[] ps = new Person[18];
// array index starting from 1 to match ids of picture at http://en.wikipedia.org/wiki/John,_King_of_England
ps[1] = new Person( 1L, "John of England" );
ps[2] = new Person( 2L, "Henry II of England" );
ps[3] = new Person( 3L, "Eleanor of Aquitaine" );
ps[4] = new Person( 4L, "Geoffrey V of Anjou" );
ps[5] = new Person( 5L, "Empress Matilda" );
ps[6] = new Person( 6L, "William X of Aquitaine" );
ps[7] = new Person( 7L, "Aenor de Châtellerault" );
ps[8] = new Person( 8L, "Fulk V of Anjou" );
ps[9] = new Person( 9L, "Ermengarde of Maine" );
ps[10] = new Person( 10L, "Henry I of England" );
ps[11] = new Person( 11L, "Matilda of Scotland" );
ps[12] = new Person( 12L, "William IX of Aquitaine" );
ps[13] = new Person( 13L, "Philippa of Toulouse" );
ps[14] = new Person( 14L, "Aimery I of Châttellerault" );
ps[15] = new Person( 15L, "Dangereuse de L'Isle Bouchard" );
ps[16] = new Person( 16L, "Fulk IV of Anjou" );
ps[17] = new Person( 17L, "Bertrade de Montfort" );
ps[1].addParents( ps[2], ps[3] );
ps[2].addParents( ps[4], ps[5] );
ps[3].addParents( ps[6], ps[7] );
ps[4].addParents( ps[8], ps[9] );
ps[5].addParents( ps[10], ps[11] );
ps[6].addParents( ps[12], ps[13] );
ps[7].addParents( ps[14], ps[15] );
ps[8].addParents( ps[16], ps[17] );
for ( int i = 1; i < 18; i++ ) {
session.save( ps[i] );
}
transaction.commit();
session.close();
for ( int i = 1; i < 18; i++ ) {
assertEquals( 1, countWorksDoneOnPerson( Long.valueOf( i ) ) );
}
}
private int countWorksDoneOnPerson(Long pk) {
List<LuceneWork> processedQueue = LeakingLuceneBackend.getLastProcessedQueue();
int count = 0;
for ( LuceneWork luceneWork : processedQueue ) {
Serializable id = luceneWork.getId();
if ( pk.equals( id ) ) {
count++;
}
}
return count;
}
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] { Person.class };
}
protected void configure(Configuration cfg) {
super.configure( cfg );
cfg.setProperty( "hibernate.search.default.worker.backend", LeakingLuceneBackend.class.getName() );
}
}