/*
* 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.backend.impl.jms;
import java.util.List;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;
import org.hibernate.search.backend.LuceneWork;
import org.hibernate.search.backend.spi.OperationDispatcher;
import org.hibernate.search.cfg.Environment;
import org.hibernate.search.spi.SearchIntegrator;
import org.hibernate.search.util.logging.impl.Log;
import org.hibernate.search.util.logging.impl.LoggerFactory;
/**
* Example template to implement the Hibernate Search controller for processing the
* work send through JMS by the slave nodes.
*
* @author Emmanuel Bernard
* @author Sanne Grinovero (C) 2011 Red Hat Inc.
*/
public abstract class AbstractJMSHibernateSearchController implements MessageListener {
private static final Log log = LoggerFactory.make();
protected abstract SearchIntegrator getSearchIntegrator();
/**
* Provides an optional extension point for the case you have to
* do some cleanup after the Message was processed.
*
* This is invoked once by {@link #onMessage(Message)} after processing
* each Message, provided the type of the Message is {@link ObjectMessage}
* as expected.
*/
protected void afterMessage() {
// No-op by default: you can override this if needed.
}
/**
* Process the Hibernate Search work queues received
*/
@Override
public void onMessage(Message message) {
if ( !( message instanceof ObjectMessage ) ) {
log.incorrectMessageType( message.getClass() );
return;
}
final ObjectMessage objectMessage = (ObjectMessage) message;
final String indexName;
final List<LuceneWork> queue;
SearchIntegrator integrator = getSearchIntegrator();
try {
indexName = extractIndexName( objectMessage );
if ( log.isDebugEnabled() ) {
logMessageDetails( objectMessage, indexName );
}
queue = integrator.getWorkSerializer().toLuceneWorks( (byte[]) objectMessage.getObject() );
/*
* We have to use a dispatcher here in order to make sure
* the sharding strategies lazily initialize new indexes as necessary
* and update their shard list.
* Thus the index name is rather useless in this case.
*/
OperationDispatcher dispatcher = getOperationDispatcher( integrator );
dispatcher.dispatch( queue, null );
}
catch (JMSException e) {
log.unableToRetrieveObjectFromMessage( message.getClass(), e );
return;
}
catch (ClassCastException e) {
log.illegalObjectRetrievedFromMessage( e );
return;
}
finally {
afterMessage();
}
}
private OperationDispatcher getOperationDispatcher(SearchIntegrator integrator) {
return integrator.createRemoteOperationDispatcher( indexManager -> true );
}
private void logMessageDetails(ObjectMessage objectMessage, String indexName) throws JMSException {
String id = objectMessage.getStringProperty( "HSearchMsgId" );
log.debug( "Message Received for index '" + indexName + "': " + id );
}
private String extractIndexName(ObjectMessage objectMessage) throws JMSException {
String name = objectMessage.getStringProperty( Environment.INDEX_NAME_JMS_PROPERTY );
if ( name == null ) {
//Fall back to try the property name we used before HSEARCH-1922
name = objectMessage.getStringProperty( "HSearchIndexName" );
}
return name;
}
}