Java tutorial
/* * 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.envers; import java.util.List; import org.apache.lucene.analysis.core.StopAnalyzer; import org.apache.lucene.queryparser.classic.ParseException; import org.apache.lucene.queryparser.classic.QueryParser; import org.apache.lucene.search.Query; import org.apache.lucene.search.Sort; import org.apache.lucene.search.SortField; import org.hibernate.Transaction; import org.hibernate.dialect.PostgreSQL81Dialect; import org.hibernate.envers.AuditReader; import org.hibernate.envers.AuditReaderFactory; import org.hibernate.envers.query.AuditEntity; import org.hibernate.search.FullTextSession; import org.hibernate.search.Search; import org.hibernate.search.test.SearchTestBase; import org.hibernate.search.testsupport.TestForIssue; import org.hibernate.testing.SkipForDialect; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; /** * Unit test covering proper behavior and integration between Hibernate Search and Envers. * As well as it verifies that the index is in sync with the latest transaction state. * * @author Davide Di Somma <davide.disomma@gmail.com> */ @SkipForDialect(jiraKey = "HSEARCH-1943", value = PostgreSQL81Dialect.class) public class SearchAndEnversIntegrationTest extends SearchTestBase { private Person harryPotter; private Person hermioneGranger; private Address privetDrive; private Address grimmauldPlace; /** * This test case aims to verify that insertion, updating and deleting operations work correctly * for both Hibernate Search and Hibernate Envers */ @TestForIssue(jiraKey = "HSEARCH-1293") @Test public void testHibernateSearchAndEnversIntegration() { atRevision1(); atRevision2(); atRevision3(); atRevision4(); } /** * It verifies that insertion operation works correctly */ private void atRevision1() { // Objects creation privetDrive = new Address("Privet Drive", 121); privetDrive.setFlatNumber(2); harryPotter = new Person("Harry", "Potter", privetDrive); grimmauldPlace = new Address("Grimmauld Place", 12); hermioneGranger = new Person("Hermione", "Granger", grimmauldPlace); { FullTextSession session = Search.getFullTextSession(openSession()); try { Transaction tx = session.beginTransaction(); session.save(privetDrive); session.save(grimmauldPlace); session.save(harryPotter); session.save(hermioneGranger); tx.commit(); } finally { session.close(); } } { FullTextSession session = Search.getFullTextSession(openSession()); try { Transaction tx = session.beginTransaction(); //Let's assert that Hibernate Envers has audited correctly AuditReader auditReader = AuditReaderFactory.get(session); assertEquals(1, findLastRevisionForEntity(auditReader, Person.class)); assertEquals(1, findLastRevisionForEntity(auditReader, Address.class)); assertEquals(2, howManyEntitiesChangedAtRevisionNumber(auditReader, Person.class, 1)); assertEquals(2, howManyEntitiesChangedAtRevisionNumber(auditReader, Address.class, 1)); assertEquals(2, howManyAuditedObjectsSoFar(auditReader, Person.class)); assertEquals(2, howManyAuditedObjectsSoFar(auditReader, Address.class)); //Let's compares that entities from Hibernate Search and last revision entities from Hibernate Envers are equals Person hermioneFromHibSearch = findPersonFromIndexBySurname(session, "Granger"); Person hermioneAtRevision1 = findPersonFromAuditBySurname(auditReader, "Granger"); assertEquals(hermioneFromHibSearch, hermioneAtRevision1); Person harryFromHibSearch = findPersonFromIndexBySurname(session, "Potter"); Person harryAtRevision1 = findPersonFromAuditBySurname(auditReader, "Potter"); assertEquals(harryFromHibSearch, harryAtRevision1); tx.commit(); } finally { session.close(); } } } /** * It verifies that updating operation on Address entity works correctly */ private void atRevision2() { // Changing the address's house number and flat number { FullTextSession session = Search.getFullTextSession(openSession()); try { Transaction tx = session.beginTransaction(); privetDrive = (Address) session.merge(privetDrive); privetDrive.setHouseNumber(5); privetDrive.setFlatNumber(null); tx.commit(); } finally { session.close(); } } { FullTextSession session = Search.getFullTextSession(openSession()); try { Transaction tx = session.beginTransaction(); AuditReader auditReader = AuditReaderFactory.get(session); //Let's assert that Hibernate Envers has audited everything correctly assertEquals(1, findLastRevisionForEntity(auditReader, Person.class)); assertEquals(2, findLastRevisionForEntity(auditReader, Address.class)); assertEquals(0, howManyEntitiesChangedAtRevisionNumber(auditReader, Person.class, 2)); assertEquals(1, howManyEntitiesChangedAtRevisionNumber(auditReader, Address.class, 2)); assertEquals(2, howManyAuditedObjectsSoFar(auditReader, Person.class)); assertEquals(3, howManyAuditedObjectsSoFar(auditReader, Address.class)); @SuppressWarnings("unchecked") List<Address> houseNumberAddressChangedAtRevision2 = auditReader.createQuery() .forEntitiesModifiedAtRevision(Address.class, 2) .add(AuditEntity.property("houseNumber").hasChanged()) .add(AuditEntity.property("flatNumber").hasChanged()) .add(AuditEntity.property("streetName").hasNotChanged()).getResultList(); assertEquals(1, houseNumberAddressChangedAtRevision2.size()); //Let's assert that Hibernate Search has indexed everything correctly List<Person> peopleLivingInPrivetDriveFromHibSearch = findPeopleFromIndexByStreetName(session, "Privet"); assertEquals(1, peopleLivingInPrivetDriveFromHibSearch.size()); //Let's compare that entities from Hibernate Search and last revision entities from Hibernate Envers are equals Person harryFromHibSearch = peopleLivingInPrivetDriveFromHibSearch.get(0); Person harryAtRevision2 = findPersonFromAuditBySurname(auditReader, "Potter"); assertEquals(harryFromHibSearch, harryAtRevision2); tx.commit(); } finally { session.close(); } } } /** * It verifies that updating operation on Person entity works correctly */ private void atRevision3() { // Moving Hermione to Harry { FullTextSession session = Search.getFullTextSession(openSession()); try { Transaction tx = session.beginTransaction(); hermioneGranger = (Person) session.merge(hermioneGranger); hermioneGranger.setAddress(privetDrive); tx.commit(); } finally { session.close(); } } { FullTextSession session = Search.getFullTextSession(openSession()); try { Transaction tx = session.beginTransaction(); AuditReader auditReader = AuditReaderFactory.get(session); //Let's assert that Hibernate Envers has audited everything correctly @SuppressWarnings("unchecked") List<Person> peopleWhoHasMovedHouseAtRevision3 = auditReader.createQuery() .forEntitiesModifiedAtRevision(Person.class, 3) .add(AuditEntity.property("address").hasChanged()).getResultList(); assertEquals(1, peopleWhoHasMovedHouseAtRevision3.size()); assertEquals(3, findLastRevisionForEntity(auditReader, Person.class)); assertEquals(3, findLastRevisionForEntity(auditReader, Address.class)); assertEquals(1, howManyEntitiesChangedAtRevisionNumber(auditReader, Person.class, 3)); assertEquals(2, howManyEntitiesChangedAtRevisionNumber(auditReader, Address.class, 3)); assertEquals(3, howManyAuditedObjectsSoFar(auditReader, Person.class)); assertEquals(5, howManyAuditedObjectsSoFar(auditReader, Address.class)); //Let's assert that Hibernate Search has indexed everything correctly List<Person> peopleLivingInPrivetDriveFromHibSearch = findPeopleFromIndexByStreetName(session, "Privet"); assertEquals(2, peopleLivingInPrivetDriveFromHibSearch.size()); tx.commit(); } finally { session.close(); } } } /** * It verifies that deleting operation on Person entity works correctly */ private void atRevision4() { // Now let's clean up everything { FullTextSession session = Search.getFullTextSession(openSession()); try { Transaction tx = session.beginTransaction(); session.delete(harryPotter); session.delete(hermioneGranger); session.delete(grimmauldPlace); session.delete(privetDrive); tx.commit(); } finally { session.close(); } } { FullTextSession session = Search.getFullTextSession(openSession()); try { Transaction tx = session.beginTransaction(); AuditReader auditReader = AuditReaderFactory.get(session); //Let's assert that Hibernate Envers has audited everything correctly assertEquals(4, findLastRevisionForEntity(auditReader, Person.class)); assertEquals(4, findLastRevisionForEntity(auditReader, Address.class)); assertEquals(2, howManyEntitiesChangedAtRevisionNumber(auditReader, Person.class, 4)); assertEquals(2, howManyEntitiesChangedAtRevisionNumber(auditReader, Address.class, 4)); assertEquals(7, howManyAuditedObjectsSoFar(auditReader, Address.class)); assertEquals(5, howManyAuditedObjectsSoFar(auditReader, Person.class)); //Let's assert that Hibernate Search has indexed everything correctly assertNull(findPersonFromIndexBySurname(session, "Potter")); assertNull(findPersonFromIndexBySurname(session, "Granger")); assertEquals(0, findPeopleFromIndexByStreetName(session, "Privet").size()); assertEquals(0, findPeopleFromIndexByStreetName(session, "Guillaume").size()); tx.commit(); } finally { session.close(); } } } /** * It returns how many entities are modified for a specific class and number revision. */ private int howManyEntitiesChangedAtRevisionNumber(AuditReader auditReader, Class<?> clazz, Number revision) { return ((Long) auditReader.createQuery().forEntitiesModifiedAtRevision(clazz, revision) .addProjection(AuditEntity.id().count()).getSingleResult()).intValue(); } /** * It returns how many audited objects are there globally for a specific class. */ private int howManyAuditedObjectsSoFar(AuditReader auditReader, Class<?> clazz) { return auditReader.createQuery().forRevisionsOfEntity(clazz, true, true).getResultList().size(); } /** * It returns the last revision for a specific class. */ private Number findLastRevisionForEntity(AuditReader auditReader, Class<?> clazz) { return (Number) auditReader.createQuery().forRevisionsOfEntity(clazz, false, true) .addProjection(AuditEntity.revisionNumber().max()).getSingleResult(); } private Person findPersonFromAuditBySurname(AuditReader auditReader, String value) { return (Person) auditReader.createQuery().forEntitiesAtRevision(Person.class, 1) .add(AuditEntity.property("surname").eq(value)).getSingleResult(); } @SuppressWarnings("unchecked") private List<Person> findPeopleFromIndex(FullTextSession session, String term, String value) { Query luceneQuery = createLuceneQuery(term, value); return session.createFullTextQuery(luceneQuery, Person.class) .setSort(new Sort(new SortField("surname", SortField.Type.STRING))).list(); } private Person findPersonFromIndexBySurname(FullTextSession session, String surname) { List<Person> people = findPeopleFromIndex(session, "surname", surname); if (people.isEmpty()) { return null; } else if (people.size() > 1) { throw new RuntimeException("I've found too many people!!!"); } return people.get(0); } private List<Person> findPeopleFromIndexByStreetName(FullTextSession session, String streetName) { return findPeopleFromIndex(session, "address.streetName", streetName); } private Query createLuceneQuery(String term, String value) { String searchQuery = term + ":" + value; QueryParser parser = new QueryParser(term, new StopAnalyzer()); Query luceneQuery; try { luceneQuery = parser.parse(searchQuery); } catch (ParseException e) { throw new RuntimeException("Unable to parse query", e); } return luceneQuery; } @Override public Class<?>[] getAnnotatedClasses() { return new Class[] { Person.class, Address.class }; } }