/*
* 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.backend.serialization;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.lucene.document.Document;
import org.easymock.EasyMock;
import org.hibernate.search.annotations.DocumentId;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.backend.AddLuceneWork;
import org.hibernate.search.backend.LuceneWork;
import org.hibernate.search.engine.integration.impl.ExtendedSearchIntegrator;
import org.hibernate.search.indexes.serialization.spi.Deserializer;
import org.hibernate.search.indexes.serialization.spi.LuceneWorkSerializer;
import org.hibernate.search.indexes.serialization.spi.SerializationProvider;
import org.hibernate.search.indexes.serialization.spi.Serializer;
import org.hibernate.search.testsupport.TestForIssue;
import org.hibernate.search.testsupport.junit.SearchFactoryHolder;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
/**
* The implementations of SerializationProvider can choose (by SPI contract) to return
* the same instance to multiple requestors as an optimisation, but this is correct to do only
* if their implementation is threadsafe.
* It's more common that implementors will opt to return different instances
* when this might be a simpler strategy to satisfy the threadsafety requirement.
*
* For such cases, we need to verify that the various clients using such a Service will not
* cache it internally in their own fields.
*
* This test verifies that an IndexManager won't reuse the instance multiple times; it won't
* cover all configurable scenarios as there are many: threadsafety can't be guaranteed than
* by careful design, so the point here is to spot the most obvious mistakes, to draw attention
* on the problem in case of creative refactoring.
*
* @author Sanne Grinovero (C) 2014 Red Hat Inc.
*/
@TestForIssue(jiraKey = "HSEARCH-1637")
public class SerializationInstanceNotReusedTest {
private final CountingSerializationProvider countingServiceInstance = new CountingSerializationProvider();
@Rule
public SearchFactoryHolder factoryHolder = new SearchFactoryHolder( Book.class )
.withService( SerializationProvider.class, countingServiceInstance );
@Test
public void testPropertiesIndexing() {
ExtendedSearchIntegrator searchFactory = factoryHolder.getSearchFactory();
LuceneWorkSerializer serializer = searchFactory.getServiceManager().requestService( LuceneWorkSerializer.class );
Assert.assertEquals( 0, countingServiceInstance.serializerGetCount.get() );
Assert.assertEquals( 0, countingServiceInstance.deserializerGetCount.get() );
//Serialize some work:
serializer.toSerializedModel( makeSomeWork() );
Assert.assertEquals( 1, countingServiceInstance.serializerGetCount.get() );
Assert.assertEquals( 0, countingServiceInstance.deserializerGetCount.get() );
//Serialize again, note the point of the test is to request all references again:
serializer.toSerializedModel( makeSomeWork() );
Assert.assertEquals( 2, countingServiceInstance.serializerGetCount.get() );
Assert.assertEquals( 0, countingServiceInstance.deserializerGetCount.get() );
//Now Deserialize:
serializer.toLuceneWorks( makeSomeSerializedWork() );
Assert.assertEquals( 2, countingServiceInstance.serializerGetCount.get() );
Assert.assertEquals( 1, countingServiceInstance.deserializerGetCount.get() );
//Now Deserialize again:
serializer.toLuceneWorks( makeSomeSerializedWork() );
Assert.assertEquals( 2, countingServiceInstance.serializerGetCount.get() );
Assert.assertEquals( 2, countingServiceInstance.deserializerGetCount.get() );
searchFactory.getServiceManager().releaseService( LuceneWorkSerializer.class );
}
private byte[] makeSomeSerializedWork() {
//Random: we won't deserialize this
return new byte[]{ 0, 1, 2};
}
private List<LuceneWork> makeSomeWork() {
List<LuceneWork> list = new LinkedList<>();
//just some random data:
list.add( new AddLuceneWork( Integer.valueOf( 5 ), "id:5", Book.class, new Document() ) );
list.add( new AddLuceneWork( Integer.valueOf( 6 ), "id:6", Book.class, new Document() ) );
return list;
}
@Indexed(index = "books")
private static class Book {
@DocumentId long id;
@Field String title;
}
/**
* This SerializationProvider mocks Serializer and Deserializer, it won't actually do the work
* but it will keep count of how many times each service is being requested.
*/
private static class CountingSerializationProvider implements SerializationProvider {
private final AtomicInteger serializerGetCount = new AtomicInteger();
private final AtomicInteger deserializerGetCount = new AtomicInteger();
private final Serializer mockSerializer = EasyMock.createNiceMock( Serializer.class );
private final Deserializer mockDeserializer = EasyMock.createNiceMock( Deserializer.class );
CountingSerializationProvider() {
EasyMock.replay( mockSerializer, mockDeserializer );
}
@Override
public Serializer getSerializer() {
serializerGetCount.incrementAndGet();
return mockSerializer;
}
@Override
public Deserializer getDeserializer() {
deserializerGetCount.incrementAndGet();
return mockDeserializer;
}
}
}