/* * 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.jgroups.master; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.UUID; import org.apache.lucene.document.Document; import org.apache.lucene.document.DoubleField; import org.apache.lucene.document.Field; import org.apache.lucene.queryparser.classic.ParseException; import org.apache.lucene.queryparser.classic.QueryParser; import org.apache.lucene.search.Query; import org.hibernate.Session; import org.hibernate.search.FullTextSession; import org.hibernate.search.Search; import org.hibernate.search.backend.AddLuceneWork; import org.hibernate.search.backend.LuceneWork; import org.hibernate.search.backend.jgroups.impl.DispatchMessageSender; import org.hibernate.search.backend.jgroups.impl.MessageSerializationHelper; import org.hibernate.search.cfg.Environment; import org.hibernate.search.engine.ProjectionConstants; import org.hibernate.search.engine.service.spi.ServiceManager; import org.hibernate.search.indexes.serialization.spi.LuceneWorkSerializer; import org.hibernate.search.spi.IndexingMode; import org.hibernate.search.test.SearchTestBase; import org.hibernate.search.test.jgroups.common.JGroupsCommonTest; import org.hibernate.search.testsupport.TestConstants; import org.hibernate.search.testsupport.concurrency.Poller; import org.hibernate.search.util.configuration.impl.ConfigurationParseHelper; import org.jgroups.JChannel; import org.jgroups.Message; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.assertEquals; /** * Tests that the Master node in a JGroups cluster can properly process messages received from channel. * <p> * * @author Lukasz Moren * @author Sanne Grinovero (C) 2011 Red Hat Inc. */ public class JGroupsMasterTest extends SearchTestBase { private static final Poller POLLER = JGroupsCommonTest.POLLER; private final QueryParser parser = new QueryParser( "id", TestConstants.stopAnalyzer ); /** * Name of the JGroups channel used in test */ public static final String CHANNEL_NAME = UUID.randomUUID().toString(); private JChannel channel; @Test public void testMessageSending() throws Exception { TShirt shirt = createObject(); List<LuceneWork> queue = createDocumentAndWorkQueue( shirt ); assertEquals( 0, countByQuery( "logo:jboss" ) ); sendMessage( queue ); POLLER.pollAssertion( () -> { Assert.assertEquals( "Message not received after waiting for long!", 1, countByQuery( "logo:jboss" ) ); } ); } private int countByQuery(String luceneQueryString) throws ParseException { FullTextSession ftSess = Search.getFullTextSession( openSession() ); try { ftSess.getTransaction().begin(); try { Query luceneQuery = parser.parse( luceneQueryString ); org.hibernate.Query query = ftSess.createFullTextQuery( luceneQuery ); List result = query.list(); return result.size(); } finally { ftSess.getTransaction().commit(); } } finally { ftSess.close(); } } private void prepareJGroupsChannel() throws Exception { channel = new JChannel( ConfigurationParseHelper.locateConfig( "testing-flush-loopback.xml" ) ); channel.connect( CHANNEL_NAME ); } private void sendMessage(List<LuceneWork> queue) throws Exception { final String indexManagerName = getIndexName(); ServiceManager serviceManager = getExtendedSearchIntegrator().getServiceManager(); //send message to all listeners byte[] data = serviceManager.requestService( LuceneWorkSerializer.class ).toSerializedModel( queue ); data = MessageSerializationHelper.prependString( indexManagerName, data ); Message message = new Message( null, null, data ); channel.send( message ); serviceManager.releaseService( LuceneWorkSerializer.class ); } protected String getIndexName() { return org.hibernate.search.test.jgroups.master.TShirt.class.getName(); } /** * Manually create the work queue. This lists gets send by the Slaves to the Master for indexing. * * @param shirt The shirt to index * * @return A manually create <code>LuceneWork</code> list. */ private List<LuceneWork> createDocumentAndWorkQueue(TShirt shirt) { Document doc = new Document(); Field field = new Field( ProjectionConstants.OBJECT_CLASS, shirt.getClass().getName(), Field.Store.YES, Field.Index.NOT_ANALYZED ); doc.add( field ); field = new Field( "id", String.valueOf( shirt.getId() ), Field.Store.YES, Field.Index.NOT_ANALYZED ); doc.add( field ); field = new Field( "logo", shirt.getLogo(), Field.Store.NO, Field.Index.ANALYZED ); doc.add( field ); DoubleField numField = new DoubleField( "length", shirt.getLength(), Field.Store.NO ); doc.add( numField ); LuceneWork luceneWork = new AddLuceneWork( shirt.getId(), String.valueOf( shirt.getId() ), shirt.getClass(), doc ); List<LuceneWork> queue = new ArrayList<LuceneWork>(); queue.add( luceneWork ); return queue; } /** * Create a test object without triggering indexing, * because Hibernate Search listeners are disabled. * * @return a <code>TShirt</code> test object. */ private TShirt createObject() { Session s = openSession(); s.getTransaction().begin(); TShirt ts = new TShirt(); ts.setLogo( "JBoss balls" ); ts.setSize( "large" ); ts.setLength( 23.2d ); s.persist( ts ); s.getTransaction().commit(); s.close(); return ts; } @Override @Before public void setUp() throws Exception { prepareJGroupsChannel(); super.setUp(); } @Override @After public void tearDown() throws Exception { channel.close(); super.tearDown(); } @Override public void configure(Map<String,Object> cfg) { // See createObject() cfg.put( Environment.INDEXING_STRATEGY, IndexingMode.MANUAL.toExternalRepresentation() ); // JGroups configuration for master node cfg.put( "hibernate.search.default." + Environment.WORKER_BACKEND, "jgroupsMaster" ); cfg.put( DispatchMessageSender.CLUSTER_NAME, CHANNEL_NAME ); cfg.put( DispatchMessageSender.CONFIGURATION_FILE, "testing-flush-loopback.xml" ); } @Override public Class<?>[] getAnnotatedClasses() { return new Class[] { TShirt.class }; } }