Author: epbernard
Date: 2007-02-26 21:17:25 -0500 (Mon, 26 Feb 2007)
New Revision: 11246
Added:
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/backend/impl/jms/AbstractJMSHibernateSearchController.java
branches/Branch_3_2/HibernateExt/search/src/test-resources/
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/directoryProvider/
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/directoryProvider/FSSwitchableAndMasterDPTest.java
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/directoryProvider/MultipleSFTestCase.java
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/directoryProvider/SnowStorm.java
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/master/
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/master/JMSMasterTest.java
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/master/MDBSearchController.java
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/master/MyHibernateUtil.java
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/master/TShirt.java
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/slave/
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/slave/JMSSlaveTest.java
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/slave/SearchQueueChecker.java
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/slave/TShirt.java
Removed:
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/backend/impl/jms/JMSHibernateSearchController.java
Modified:
branches/Branch_3_2/HibernateExt/search/build.xml
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/backend/impl/jms/JMSBackendQueueProcessorFactory.java
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/query/FullTextQueryImpl.java
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/store/FSMasterDirectoryProvider.java
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/store/FSSwitchableDirectoryProvider.java
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/util/DirectoryProviderHelper.java
Log:
Add JMS test
Add Switchable directory test
Modified: branches/Branch_3_2/HibernateExt/search/build.xml
===================================================================
--- branches/Branch_3_2/HibernateExt/search/build.xml 2007-02-25 10:26:24 UTC (rev 11245)
+++ branches/Branch_3_2/HibernateExt/search/build.xml 2007-02-27 02:17:25 UTC (rev 11246)
@@ -22,7 +22,7 @@
<property name="javac.source" value="1.5"/>
<property name="javac.target" value="1.5"/>
<property name="jdbc.dir" value="jdbc"/>
- <property name="common.dir" value="${basedir}/../common"/>
+ <property name="common.dir" value="${basedir}/../common"/>
<property name="jpa-api.jar"
value="${basedir}/../jpa-api/build/ejb3-persistence.jar"/>
<property name="annotations.jar"
@@ -32,23 +32,54 @@
<import file="${common.dir}/common-build.xml"/>
+
+ <property name="build.testresources.dir"
value="${build.dir}/testresources"/>
+ <property name="testresources.dir"
value="${basedir}/src/test-resources"/>
- <path id="lib.moduleclass.path">
+ <!-- override order for JBossXB to bootstrap properly -->
+ <path id="junit.classpath">
+ <fileset dir="${lib.dir}">
+ <include name="*.jar"/>
+ </fileset>
+ <pathelement path="${classes.dir}"/>
+ <pathelement path="${testclasses.dir}"/>
+ <path refid="junit.moduleclasspath"/>
+ <path refid="lib.class.path"/>
+ <path location="${clover.jar}"/>
+ </path>
+ <!-- override order for JBossXB to bootstrap properly -->
+ <path id="lib.class.path">
+ <path location="${hibernate-core.jar}"></path>
+ <fileset dir="${hibernate-core.lib.dir}">
+ <include name="*.jar"/>
+ <exclude name="xml-apis.jar"/>
+ <exclude name="xerces*.jar"/>
+ </fileset>
+ <fileset dir="${lib.dir}">
+ <include name="*.jar"/>
+ </fileset>
+ <path refid="lib.moduleclass.path"/>
+ <pathelement path="${clover.jar}"/>
+ </path>
+
+
+ <path id="lib.moduleclass.path">
<pathelement location="${jpa-api.jar}"/>
<pathelement location="${commons-annotations.jar}"/>
</path>
<path id="junit.moduleclasspath">
- <pathelement location="${src.dir}"/>
+ <!-- order matters for JBoss XB proper bootstrap -->
+ <fileset dir="${lib.dir}/test">
+ <include name="*.jar"/>
+ <include name="*.zip"/>
+ </fileset>
+ <pathelement location="${src.dir}"/>
<pathelement location="${test.dir}"/>
<pathelement location="${annotations.jar}"/>
<fileset dir="${jdbc.dir}">
<include name="*.jar"/>
<include name="*.zip"/>
</fileset>
- <fileset dir="${lib.dir}/test">
- <include name="*.jar"/>
- <include name="*.zip"/>
- </fileset>
</path>
<target name="init">
@@ -58,6 +89,7 @@
<available file="${commons-annotations.jar}" type="file"
property="commons-annotations.jar.available"/>
<available file="${annotations.jar}" type="file"
property="annotations.jar.available"/>
<mkdir dir="${lib.dir}/test"/>
+ <mkdir dir="${build.testresources.dir}"/>
</target>
<target name="get.jpa-api" depends="init"
unless="jpa-api.jar.available">
@@ -118,30 +150,48 @@
</javac>
</target>
+ <target name="prepare-test-resources"
depends="compiletest">
+ <copy todir="${build.testresources.dir}">
+ <fileset dir="${testresources.dir}">
+ <include name="**/*.*"/>
+ </fileset>
+ </copy>
+ <mkdir dir="${build.testresources.dir}/jars"/>
+ <jar filesetmanifest="merge"
jarfile="${build.testresources.dir}/jars/jms-slave.jar" >
+ <fileset dir="${testclasses.dir}">
+ <include
name="org/hibernate/search/test/jms/slave/**.*"/>
+ </fileset>
+ </jar>
+ <jar filesetmanifest="merge"
jarfile="${build.testresources.dir}/jars/jms-master.jar" >
+ <fileset dir="${testclasses.dir}">
+ <include
name="org/hibernate/search/test/jms/master/**.*"/>
+ </fileset>
+ </jar>
+ </target>
- <!-- target name="junit" depends="compiletest">
- <mkdir dir="test_output"/>
- <junit fork="yes" printsummary="yes"
haltonfailure="yes"
- forkmode="perBatch">
- <classpath>
- <fileset dir="${jdbc.dir}">
- <include name="**/*.jar"/>
- <include name="**/*.zip"/>
- </fileset>
- <path refid="lib.class.path"/>
- <pathelement path="${classes.dir}"/>
- <pathelement path="${src.dir}"/>
- <pathelement path="${test.dir}"/>
- </classpath>
- <formatter type="plain"/>
- <formatter type="xml"/>
- <batchtest fork="yes" todir="test_output"
haltonfailure="no">
- <fileset dir="${classes.dir}">
- <include name="**/*Test.class"/>
- </fileset>
- </batchtest>
- </junit>
- </target -->
+ <target name="junit" depends="compiletest,
prepare-test-resources">
+ <mkdir dir="test_output"/>
+ <junit forkmode="once" printsummary="yes"
haltonfailure="yes">
+ <classpath>
+ <path path="${build.testresources.dir}"/>
+ <!-- dirset dir="${build.testresources.dir}">
+ <include name="**/*.jar"/>
+ <include name="**/*.par"/>
+ </dirset -->
+ <path refid="junit.classpath"/>
+
+ <fileset dir="${jdbc.dir}">
+ <include name="**/*.jar"/>
+ <include name="**/*.zip"/>
+ </fileset>
+ </classpath>
+ <formatter type="plain"/>
+ <formatter type="xml"/>
+ <batchtest fork="yes" todir="test_output"
haltonfailure="no">
+ <fileset refid="junit.batchtestset"/>
+ </batchtest>
+ </junit>
+ </target>
<!-- Run a single unit test. -->
<target name="junitsingle" depends="compiletest"
Copied:
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/backend/impl/jms/AbstractJMSHibernateSearchController.java
(from rev 11235,
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/backend/impl/jms/JMSHibernateSearchController.java)
===================================================================
---
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/backend/impl/jms/AbstractJMSHibernateSearchController.java
(rev 0)
+++
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/backend/impl/jms/AbstractJMSHibernateSearchController.java 2007-02-27
02:17:25 UTC (rev 11246)
@@ -0,0 +1,111 @@
+//$Id: $
+package org.hibernate.search.backend.impl.jms;
+
+import java.util.List;
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.ObjectMessage;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.hibernate.Session;
+import org.hibernate.search.SearchFactory;
+import org.hibernate.search.backend.Work;
+import org.hibernate.search.util.ContextHelper;
+
+/**
+ * Implement the Hibernate Search controller responsible for processing the
+ * work send through JMS by the slave nodes.
+ *
+ * Note the subclass implementation has to implements javax.jms.MessageListener
+ * //TODO Ask Bill why it is required
+ *
+ * @author Emmanuel Bernard
+ */
+public abstract class AbstractJMSHibernateSearchController implements MessageListener {
+ private static Log log = LogFactory.getLog( AbstractJMSHibernateSearchController.class
);
+
+ /**
+ * return the current or give a new session
+ * This session is not used per se, but is the link to access the Search configuration
+ *
+ * A typical EJB 3.0 usecase would be to get the session from the container (injected)
+ * eg in JBoss EJB 3.0
+ * <code>
+ * @PersistenceContext private Session session;
+ *
+ * protected Session getSession() {
+ * return session
+ * }
+ *
+ * eg in any container
+ * <code>
+ * @PersistenceContext private EntityManager entityManager;
+ *
+ * protected Session getSession() {
+ * return (Session) entityManager.getdelegate();
+ * }
+ */
+ protected abstract Session getSession();
+
+ /**
+ * Ensure to clean the resources after use.
+ * If the session has been directly or indirectly injected, this method is empty
+ */
+ protected abstract void cleanSessionIfNeeded(Session session);
+
+ /**
+ * Process the Hibernate Search work queues received
+ */
+ public void onMessage(Message message) {
+ if ( !( message instanceof ObjectMessage ) ) {
+ log.error( "Incorrect message type: " + message.getClass() );
+ return;
+ }
+ ObjectMessage objectMessage = (ObjectMessage) message;
+ List<Work> queue;
+ try {
+ queue = (List<Work>) objectMessage.getObject();
+ }
+ catch (JMSException e) {
+ log.error( "Unable to retrieve object from message: " + message.getClass(),
e );
+ return;
+ }
+ catch (ClassCastException e) {
+ log.error( "Illegal object retrieved from message", e );
+ return;
+ }
+ Runnable worker = getWorker( queue );
+ worker.run();
+ }
+
+ private Runnable getWorker(List<Work> queue) {
+ //FIXME casting sucks becasue we do not control what get session from
+ Session session = getSession();
+ Runnable processor = null;
+
+ try {
+ SearchFactory factory = ContextHelper.getSearchFactory( session );
+ processor = factory.getBackendQueueProcessorFactory().getProcessor( queue );
+ }
+ finally {
+ cleanSessionIfNeeded(session);
+ }
+ return processor;
+ }
+
+ @PostConstruct
+ public void initialize() {
+ //init the source copy process
+ //TODO actually this is probably wrong since this is now part of the DP
+ }
+
+ @PreDestroy
+ public void shutdown() {
+ //stop the source copy process
+ //TODO actually this is probably wrong since this is now part of the DP
+ }
+}
Modified:
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/backend/impl/jms/JMSBackendQueueProcessorFactory.java
===================================================================
---
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/backend/impl/jms/JMSBackendQueueProcessorFactory.java 2007-02-25
10:26:24 UTC (rev 11245)
+++
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/backend/impl/jms/JMSBackendQueueProcessorFactory.java 2007-02-27
02:17:25 UTC (rev 11246)
@@ -11,10 +11,9 @@
import javax.naming.InitialContext;
import javax.naming.NamingException;
-import org.hibernate.HibernateException;
import org.hibernate.search.Environment;
+import org.hibernate.search.SearchException;
import org.hibernate.search.SearchFactory;
-import org.hibernate.search.SearchException;
import org.hibernate.search.backend.BackendQueueProcessorFactory;
import org.hibernate.search.backend.Work;
@@ -40,7 +39,7 @@
}
public Runnable getProcessor(List<Work> queue) {
- return new JMSBackendQueueProcessor(queue, this);
+ return new JMSBackendQueueProcessor( queue, this );
}
@@ -58,22 +57,30 @@
}
public void prepareJMSTools() {
- if (jmsQueue != null && factory != null) return;
+ if ( jmsQueue != null && factory != null ) return;
try {
- InitialContext initialContext = getInitialContext(properties);
+ InitialContext initialContext = getInitialContext( properties );
factory = (QueueConnectionFactory) initialContext.lookup( jmsConnectionFactoryName );
jmsQueue = (Queue) initialContext.lookup( jmsQueueName );
}
catch (NamingException e) {
- throw new SearchException("Unable to lookup Search queue and connection
factory", e);
+ throw new SearchException( "Unable to lookup Search queue ("
+ + ( jmsQueueName != null ?
+ jmsQueueName :
+ "null" ) + ") and connection factory ("
+ + ( jmsConnectionFactoryName != null ?
+ jmsConnectionFactoryName :
+ "null" ) + ")",
+ e
+ );
}
}
private InitialContext getInitialContext(Properties properties) throws NamingException
{
Properties jndiProps = getJndiProperties( properties );
- if (jndiProps.size() == 0) {
- return new InitialContext( );
+ if ( jndiProps.size() == 0 ) {
+ return new InitialContext();
}
else {
return new InitialContext( jndiProps );
@@ -90,21 +97,21 @@
Properties result = new Properties();
while ( iter.hasNext() ) {
String prop = (String) iter.next();
- if ( prop.indexOf(JNDI_PREFIX) > -1 && !specialProps.contains(prop) ) {
+ if ( prop.indexOf( JNDI_PREFIX ) > -1 && !specialProps.contains( prop ) )
{
result.setProperty(
- prop.substring( JNDI_PREFIX.length()+1 ),
- properties.getProperty(prop)
- );
+ prop.substring( JNDI_PREFIX.length() + 1 ),
+ properties.getProperty( prop )
+ );
}
}
- String jndiClass = properties.getProperty(JNDI_PREFIX + "class");
- String jndiURL = properties.getProperty(JNDI_PREFIX + "url");
+ String jndiClass = properties.getProperty( JNDI_PREFIX + "class" );
+ String jndiURL = properties.getProperty( JNDI_PREFIX + "url" );
// we want to be able to just use the defaults,
// if JNDI environment properties are not supplied
// so don't put null in anywhere
- if (jndiClass != null) result.put( Context.INITIAL_CONTEXT_FACTORY, jndiClass);
- if (jndiURL != null) result.put(Context.PROVIDER_URL, jndiURL);
+ if ( jndiClass != null ) result.put( Context.INITIAL_CONTEXT_FACTORY, jndiClass );
+ if ( jndiURL != null ) result.put( Context.PROVIDER_URL, jndiURL );
return result;
}
Deleted:
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/backend/impl/jms/JMSHibernateSearchController.java
===================================================================
---
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/backend/impl/jms/JMSHibernateSearchController.java 2007-02-25
10:26:24 UTC (rev 11245)
+++
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/backend/impl/jms/JMSHibernateSearchController.java 2007-02-27
02:17:25 UTC (rev 11246)
@@ -1,67 +0,0 @@
-//$Id: $
-package org.hibernate.search.backend.impl.jms;
-
-import java.util.List;
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import javax.jms.JMSException;
-import javax.jms.Message;
-import javax.jms.MessageListener;
-import javax.jms.ObjectMessage;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.hibernate.Session;
-import org.hibernate.engine.SessionImplementor;
-import org.hibernate.search.SearchFactory;
-import org.hibernate.search.backend.Work;
-import org.hibernate.search.util.ContextHelper;
-
-/**
- * @author Emmanuel Bernard
- */
-public abstract class JMSHibernateSearchController implements MessageListener {
- private static Log log = LogFactory.getLog( JMSHibernateSearchController.class );
-
- protected abstract Session getSession();
-
- public void onMessage(Message message) {
- if ( !( message instanceof ObjectMessage ) ) {
- log.error( "Incorrect message type: " + message.getClass() );
- return;
- }
- ObjectMessage objectMessage = (ObjectMessage) message;
- List<Work> queue;
- try {
- queue = (List<Work>) objectMessage.getObject();
- }
- catch (JMSException e) {
- log.error( "Unable to retrieve object from message: " + message.getClass(),
e );
- return;
- }
- catch (ClassCastException e) {
- log.error( "Illegal object retrieved from message", e );
- return;
- }
- Runnable worker = getWorker( queue );
- worker.run();
- }
-
- private Runnable getWorker(List<Work> queue) {
- //FIXME casting sucks becasue we do not control what get session from
- SearchFactory factory = ContextHelper.getSearchFactoryBySFI( (SessionImplementor)
getSession() );
- return factory.getBackendQueueProcessorFactory().getProcessor( queue );
- }
-
- @PostConstruct
- public void initialize() {
- //init the source copy process
- //TODO actually this is probably wrong since this is now part of the DP
- }
-
- @PreDestroy
- public void shutdown() {
- //stop the source copy process
- //TODO actually this is probably wrong since this is now part of the DP
- }
-}
Modified:
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/query/FullTextQueryImpl.java
===================================================================
---
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/query/FullTextQueryImpl.java 2007-02-25
10:26:24 UTC (rev 11245)
+++
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/query/FullTextQueryImpl.java 2007-02-27
02:17:25 UTC (rev 11246)
@@ -55,7 +55,7 @@
* classes must be immutable
*/
public FullTextQueryImpl(org.apache.lucene.search.Query query, Class[] classes,
SessionImplementor session,
- ParameterMetadata parameterMetadata) {
+ ParameterMetadata parameterMetadata) {
//TODO handle flushMode
super( query.toString(), null, session, parameterMetadata );
this.luceneQuery = query;
@@ -75,6 +75,9 @@
SearchFactory searchFactory = ContextHelper.getSearchFactoryBySFI( session );
//find the directories
Searcher searcher = buildSearcher( searchFactory );
+ if ( searcher == null ) {
+ return new IteratorImpl( new ArrayList<EntityInfo>(0), (Session)
this.session);
+ }
try {
org.apache.lucene.search.Query query = filterQueryByClasses( luceneQuery );
Hits hits = searcher.search( query );
@@ -95,20 +98,24 @@
throw new HibernateException( "Unable to query Lucene index", e );
}
finally {
- if ( searcher != null ) try {
- searcher.close();
+ if ( searcher != null ) {
+ try {
+ searcher.close();
+ }
+ catch (IOException e) {
+ log.warn( "Unable to properly close searcher during lucene query: " +
getQueryString(), e );
+ }
}
- catch (IOException e) {
- log.warn( "Unable to properly close searcher during lucene query: " +
getQueryString(), e );
- }
}
}
- public ScrollableResults scroll() throws HibernateException {
+ public ScrollableResults scroll() throws HibernateException {
//keep the searcher open until the resultset is closed
- SearchFactory searchFactory = ContextHelper.getSearchFactoryBySFI( session );;
+ SearchFactory searchFactory = ContextHelper.getSearchFactoryBySFI( session );
+ ;
//find the directories
Searcher searcher = buildSearcher( searchFactory );
+ //FIXME: handle null searcher
Hits hits;
try {
org.apache.lucene.search.Query query = filterQueryByClasses( luceneQuery );
@@ -135,9 +142,10 @@
}
public List list() throws HibernateException {
- SearchFactory searchFactory = ContextHelper.getSearchFactoryBySFI( session );;
+ SearchFactory searchFactory = ContextHelper.getSearchFactoryBySFI( session );
//find the directories
Searcher searcher = buildSearcher( searchFactory );
+ if (searcher == null) return new ArrayList(0);
Hits hits;
try {
org.apache.lucene.search.Query query = filterQueryByClasses( luceneQuery );
@@ -156,21 +164,21 @@
//we don't face proxy casting issues since the exact class is extracted from the
index
}
//then initialize the objects
- List excludedObects = new ArrayList();
- for ( Object element : result ) {
- try {
- Hibernate.initialize( element );
- }
- catch (ObjectNotFoundException e) {
- log.debug( "Object found in Search index but not in database: "
- + e.getEntityName() + " wih id " + e.getIdentifier() );
- excludedObects.add( element );
- }
- }
- if (excludedObects.size() > 0) {
- result.removeAll( excludedObects );
- }
- return result;
+ List excludedObects = new ArrayList();
+ for ( Object element : result ) {
+ try {
+ Hibernate.initialize( element );
+ }
+ catch (ObjectNotFoundException e) {
+ log.debug( "Object found in Search index but not in database: "
+ + e.getEntityName() + " wih id " + e.getIdentifier() );
+ excludedObects.add( element );
+ }
+ }
+ if ( excludedObects.size() > 0 ) {
+ result.removeAll( excludedObects );
+ }
+ return result;
}
catch (IOException e) {
throw new HibernateException( "Unable to query Lucene index", e );
@@ -264,7 +272,7 @@
throw new HibernateException( "Unable to read Lucene directory", e );
}
}
- else {
+ else if ( dirNbr == 1 ) {
try {
searcher = new IndexSearcher( directories.iterator().next() );
}
@@ -272,6 +280,9 @@
throw new HibernateException( "Unable to read Lucene directory", e );
}
}
+ else {
+ return null; //no indexed entity set up
+ }
return searcher;
}
Modified:
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/store/FSMasterDirectoryProvider.java
===================================================================
---
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/store/FSMasterDirectoryProvider.java 2007-02-25
10:26:24 UTC (rev 11245)
+++
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/store/FSMasterDirectoryProvider.java 2007-02-27
02:17:25 UTC (rev 11246)
@@ -24,9 +24,12 @@
* Use a Lucene FSDirectory
* The base directory is represented by hibernate.search.<index>.indexBase
* The index is created in <base directory>/<index name>
+ * The copy directory is built from <sourceBase>/<index name>
+ * TODO explose source
*
* @author Emmanuel Bernard
*/
+//TODO rename copy?
public class FSMasterDirectoryProvider implements DirectoryProvider<FSDirectory> {
private static Log log = LogFactory.getLog( FSMasterDirectoryProvider.class );
private FSDirectory directory;
@@ -37,13 +40,16 @@
public void initialize(String directoryProviderName, Properties properties,
SearchFactory searchFactory) {
//source guessing
- String source = DirectoryProviderHelper.getSourceDirectory( "sourceBase",
"source", properties );
- if (source == null)
+ String source = DirectoryProviderHelper.getSourceDirectory( "sourceBase",
"source", directoryProviderName, properties );
+ if ( source == null)
throw new IllegalStateException("FSMasterDirectoryProvider requires a viable
source directory");
+ log.debug( "Source directory: " + source );
File indexDir = DirectoryProviderHelper.determineIndexDir( directoryProviderName,
properties );
+ log.debug( "Index directory: " + indexDir );
String refreshPeriod = properties.getProperty( "refresh", "60" );
long period = Long.parseLong( refreshPeriod );
-
+ period *= 100 * 60; //per minute
+ log.debug("Refresh period " + period / 1000 + " mins");
try {
boolean create = !indexDir.exists();
indexName = indexDir.getCanonicalPath();
@@ -58,10 +64,10 @@
}
//copy to source
- if ( new File(source, "current1").exists() ) {
+ if ( new File( source, "current1").exists() ) {
current = 2;
}
- else if ( new File(source, "current2").exists() ) {
+ else if ( new File( source, "current2").exists() ) {
current = 1;
}
else {
@@ -69,12 +75,12 @@
current = 1;
}
String currentString = Integer.valueOf( current ).toString();
- File subDir = new File(source, currentString );
+ File subDir = new File( source, currentString );
FileHelper.synchronize( indexDir, subDir, true );
- new File(source, "current1").delete();
- new File(source, "current2").delete();
+ new File( source, "current1").delete();
+ new File( source, "current2").delete();
//TODO small hole, no file can be found here
- new File(source, "current" + currentString).createNewFile();
+ new File( source, "current" + currentString).createNewFile();
log.debug( "Current directory: " + current);
}
catch (IOException e) {
@@ -144,6 +150,7 @@
public void run() {
//TODO get rid of current and use the marker file instead?
+ long start = System.currentTimeMillis();
inProgress = true;
if (directoryProviderLock == null) {
directoryProviderLock = searchFactory.getLockableDirectoryProviders().get(
directoryProvider );
@@ -159,6 +166,7 @@
File destinationFile = new File(destination, Integer.valueOf(index).toString() );
//TODO make smart a parameter
try {
+ log.trace("Copying " + sourceFile + " into " +
destinationFile);
FileHelper.synchronize( sourceFile, destinationFile, true);
current = index;
}
@@ -168,11 +176,11 @@
inProgress = false;
return;
}
- if ( ! new File(source, "current" + oldIndex).delete() ) {
+ if ( ! new File(destination, "current" + oldIndex).delete() ) {
log.warn( "Unable to remove previous marker file from source of " +
indexName );
}
try {
- new File(source, "current" + index).createNewFile();
+ new File(destination, "current" + index).createNewFile();
}
catch( IOException e ) {
log.warn( "Unable to create current marker in source of " + indexName, e
);
@@ -182,6 +190,7 @@
directoryProviderLock.unlock();
inProgress = false;
}
+ log.trace( "Copy for " + indexName + " took " +
(System.currentTimeMillis() - start) + " ms");
}
}
Modified:
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/store/FSSwitchableDirectoryProvider.java
===================================================================
---
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/store/FSSwitchableDirectoryProvider.java 2007-02-25
10:26:24 UTC (rev 11245)
+++
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/store/FSSwitchableDirectoryProvider.java 2007-02-27
02:17:25 UTC (rev 11246)
@@ -37,20 +37,26 @@
public void initialize(String directoryProviderName, Properties properties,
SearchFactory searchFactory) {
//source guessing
- String source = DirectoryProviderHelper.getSourceDirectory( "sourceBase",
"source", properties );
+ String source = DirectoryProviderHelper.getSourceDirectory( "sourceBase",
"source", directoryProviderName, properties );
if (source == null)
throw new IllegalStateException("FSSwitchableDirectoryProvider requires a viable
source directory");
if ( ! new File(source, "current1").exists() && ! new File(source,
"current2").exists() ) {
throw new IllegalStateException("No current marker in source directory");
}
+ log.debug( "Source directory: " + source );
File indexDir = DirectoryProviderHelper.determineIndexDir( directoryProviderName,
properties );
+ log.debug( "Index directory: " + indexDir.getPath() );
String refreshPeriod = properties.getProperty( "refresh", "60" );
long period = Long.parseLong( refreshPeriod );
-
+ period *= 100 * 60; //per minute
+ log.debug("Refresh period " + period / 60000 + " mins");
try {
boolean create = !indexDir.exists();
indexName = indexDir.getCanonicalPath();
- if (create) indexDir.mkdir();
+ if (create) {
+ indexDir.mkdir();
+ log.debug("Initializing index directory " + indexName);
+ }
File subDir = new File( indexName, "1" );
create = ! subDir.exists();
@@ -81,9 +87,18 @@
current = 1;
File sourceFile = new File(source);
File destinationFile = new File(indexName, Integer.valueOf(current).toString() );
- //TODO make smart a parameter
+ int sourceCurrent;
+ if ( new File(sourceFile, "current1").exists() ) {
+ sourceCurrent = 1;
+ }
+ else if ( new File(sourceFile, "current2").exists() ) {
+ sourceCurrent = 2;
+ }
+ else {
+ throw new AssertionFailure("No current file marker found in source directory:
" + source);
+ }
try {
- FileHelper.synchronize( sourceFile, destinationFile, true);
+ FileHelper.synchronize( new File(sourceFile, String.valueOf(sourceCurrent) ),
destinationFile, true);
}
catch (IOException e) {
throw new HibernateException("Umable to synchonize directory: " +
indexName, e);
@@ -148,7 +163,7 @@
executor.execute( copyTask );
}
else {
- log.info( "Skipping directory synchronization, previous work still in progress:
" + indexName);
+ log.trace( "Skipping directory synchronization, previous work still in progress:
" + indexName);
}
}
}
@@ -164,6 +179,7 @@
}
public void run() {
+ long start = System.currentTimeMillis();
try {
inProgress = true;
int oldIndex = current;
@@ -184,6 +200,7 @@
File destinationFile = new File(destination, Integer.valueOf(index).toString() );
//TODO make smart a parameter
try {
+ log.trace("Copying " + sourceFile + " into " +
destinationFile);
FileHelper.synchronize( sourceFile, destinationFile, true);
current = index;
}
@@ -206,6 +223,7 @@
finally {
inProgress = false;
}
+ log.trace( "Copy for " + indexName + " took " +
(System.currentTimeMillis() - start) + " ms");
}
}
Modified:
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/util/DirectoryProviderHelper.java
===================================================================
---
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/util/DirectoryProviderHelper.java 2007-02-25
10:26:24 UTC (rev 11245)
+++
branches/Branch_3_2/HibernateExt/search/src/java/org/hibernate/search/util/DirectoryProviderHelper.java 2007-02-27
02:17:25 UTC (rev 11246)
@@ -8,6 +8,8 @@
import org.hibernate.HibernateException;
import org.hibernate.AssertionFailure;
+import org.hibernate.search.SearchException;
+import org.hibernate.annotations.common.util.StringHelper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -21,7 +23,8 @@
* and checking for the file availability
*
*/
- public static String getSourceDirectory(String rootPropertyName, String
relativePropertyName, Properties properties) {
+ public static String getSourceDirectory(String rootPropertyName, String
relativePropertyName,
+ String directoryProviderName, Properties properties) {
//TODO check that it's a directory
String root = properties.getProperty( rootPropertyName );
String relative = properties.getProperty( relativePropertyName );
@@ -31,8 +34,8 @@
+ " and " + relativePropertyName + " " + relative != null ?
relative : "<null>"
);
}
- if (relative == null) throw new HibernateException("source property
mandatory");
- if (root == null) {
+ if (relative == null) relative = directoryProviderName;
+ if ( StringHelper.isEmpty( root ) ) {
log.debug( "No root directory, go with relative " + relative );
File sourceFile = new File(relative);
if ( ! sourceFile.exists() ) {
@@ -41,8 +44,10 @@
//else keep source as it
}
else {
- File sourceFile = new File(root, relative);
- if ( sourceFile.exists() ) {
+ File rootDir = new File(root);
+ if ( rootDir.exists() ) {
+ File sourceFile = new File(root, relative);
+ if (! sourceFile.exists() ) sourceFile.mkdir();
log.debug( "Get directory from root + relative");
try {
relative = sourceFile.getCanonicalPath();
@@ -52,12 +57,7 @@
}
}
else {
- sourceFile = new File(relative);
- log.debug( "Get directory from relative only");
- if ( ! sourceFile.exists() ) {
- throw new HibernateException("Unable to read source directory: " +
relative);
- }
- //else keep source as it
+ throw new SearchException(rootPropertyName + " does not exist");
}
}
return relative;
Added:
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/directoryProvider/FSSwitchableAndMasterDPTest.java
===================================================================
---
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/directoryProvider/FSSwitchableAndMasterDPTest.java
(rev 0)
+++
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/directoryProvider/FSSwitchableAndMasterDPTest.java 2007-02-27
02:17:25 UTC (rev 11246)
@@ -0,0 +1,143 @@
+//$Id: $
+package org.hibernate.search.test.directoryProvider;
+
+import java.io.File;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.lucene.analysis.StopAnalyzer;
+import org.apache.lucene.queryParser.QueryParser;
+import org.hibernate.Session;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.event.PostDeleteEventListener;
+import org.hibernate.event.PostInsertEventListener;
+import org.hibernate.event.PostUpdateEventListener;
+import org.hibernate.search.FullTextSession;
+import org.hibernate.search.Search;
+import org.hibernate.search.util.FileHelper;
+import org.hibernate.search.event.FullTextIndexEventListener;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class FSSwitchableAndMasterDPTest extends MultipleSFTestCase {
+
+ public void testProperCopy() throws Exception {
+ Session s1 = getSessionFactories()[0].openSession( );
+ SnowStorm sn = new SnowStorm();
+ sn.setDate( new Date() );
+ sn.setLocation( "Dallas, TX, USA");
+
+ FullTextSession fts2 = Search.createFullTextSession(
getSessionFactories()[1].openSession( ) );
+ QueryParser parser = new QueryParser("id", new StopAnalyzer() );
+ List result = fts2.createFullTextQuery( parser.parse( "location:texas" )
).list();
+ assertEquals( "No copy yet, fresh index expected", 0, result.size() );
+
+ s1.persist( sn );
+ s1.flush(); //we don' commit so we need to flush manually
+
+ fts2.close();
+ s1.close();
+
+ Thread.sleep( 2 * 60 * 100 + 10); //wait a bit more than 2 refresh (one master / one
slave)
+
+ //temp test original
+ fts2 = Search.createFullTextSession( getSessionFactories()[0].openSession( ) );
+ result = fts2.createFullTextQuery( parser.parse( "location:dallas" )
).list();
+ assertEquals( "Original should get one", 1, result.size() );
+
+ fts2 = Search.createFullTextSession( getSessionFactories()[1].openSession( ) );
+ result = fts2.createFullTextQuery( parser.parse( "location:dallas" )
).list();
+ assertEquals("First copy did not work out", 1, result.size() );
+
+ s1 = getSessionFactories()[0].openSession( );
+ sn = new SnowStorm();
+ sn.setDate( new Date() );
+ sn.setLocation( "Chennai, India");
+
+ s1.persist( sn );
+ s1.flush(); //we don' commit so we need to flush manually
+
+ fts2.close();
+ s1.close();
+
+ Thread.sleep( 2 * 60 * 100 + 10); //wait a bit more than 2 refresh (one master / one
slave)
+
+ fts2 = Search.createFullTextSession( getSessionFactories()[1].openSession( ) );
+ result = fts2.createFullTextQuery( parser.parse( "location:chennai" )
).list();
+ assertEquals("Second copy did not work out", 1, result.size() );
+
+ s1 = getSessionFactories()[0].openSession( );
+ sn = new SnowStorm();
+ sn.setDate( new Date() );
+ sn.setLocation( "Melbourne, Australia");
+
+ s1.persist( sn );
+ s1.flush(); //we don' commit so we need to flush manually
+
+ fts2.close();
+ s1.close();
+
+ Thread.sleep( 2 * 60 * 100 + 10); //wait a bit more than 2 refresh (one master / one
slave)
+
+ fts2 = Search.createFullTextSession( getSessionFactories()[1].openSession( ) );
+ result = fts2.createFullTextQuery( parser.parse( "location:melbourne" )
).list();
+ assertEquals("Third copy did not work out", 1, result.size() );
+
+ fts2.close();
+ }
+
+
+ protected void setUp() throws Exception {
+ File base = new File(".");
+ File root = new File(base, "lucenedirs");
+ root.mkdir();
+
+ File master = new File(root, "master/main");
+ master.mkdirs();
+ master = new File(root, "master/copy");
+ master.mkdirs();
+
+ File slave = new File(root, "slave");
+ slave.mkdir();
+
+ super.setUp();
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ File base = new File(".");
+ File root = new File(base, "lucenedirs");
+ FileHelper.delete( root );
+ }
+
+ protected int getSFNbrs() {
+ return 2;
+ }
+
+ protected Class[] getMappings() {
+ return new Class[] {
+ SnowStorm.class
+ };
+ }
+
+ protected void configure(Configuration[] cfg) {
+ //master
+ cfg[0].setProperty( "hibernate.search.default.sourceBase",
"./lucenedirs/master/copy");
+ cfg[0].setProperty( "hibernate.search.default.indexBase",
"./lucenedirs/master/main");
+ cfg[0].setProperty( "hibernate.search.default.refresh", "1");
//every minute
+ cfg[0].setProperty( "hibernate.search.default.directory_provider",
"org.hibernate.search.store.FSMasterDirectoryProvider");
+ cfg[0].getEventListeners().setPostDeleteEventListeners( new PostDeleteEventListener[]{
new FullTextIndexEventListener() } );
+ cfg[0].getEventListeners().setPostUpdateEventListeners( new PostUpdateEventListener[]{
new FullTextIndexEventListener() } );
+ cfg[0].getEventListeners().setPostInsertEventListeners( new PostInsertEventListener[]{
new FullTextIndexEventListener() } );
+
+ //slave(s)
+ cfg[1].setProperty( "hibernate.search.default.sourceBase",
"./lucenedirs/master/copy");
+ cfg[1].setProperty( "hibernate.search.default.indexBase",
"./lucenedirs/slave");
+ cfg[1].setProperty( "hibernate.search.default.refresh", "1");
//every minute
+ cfg[1].setProperty( "hibernate.search.default.directory_provider",
"org.hibernate.search.store.FSSwitchableDirectoryProvider");
+ cfg[1].getEventListeners().setPostDeleteEventListeners( new PostDeleteEventListener[]{
new FullTextIndexEventListener() } );
+ cfg[1].getEventListeners().setPostUpdateEventListeners( new PostUpdateEventListener[]{
new FullTextIndexEventListener() } );
+ cfg[1].getEventListeners().setPostInsertEventListeners( new PostInsertEventListener[]{
new FullTextIndexEventListener() } );
+ }
+}
Added:
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/directoryProvider/MultipleSFTestCase.java
===================================================================
---
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/directoryProvider/MultipleSFTestCase.java
(rev 0)
+++
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/directoryProvider/MultipleSFTestCase.java 2007-02-27
02:17:25 UTC (rev 11246)
@@ -0,0 +1,95 @@
+//$Id: $
+package org.hibernate.search.test.directoryProvider;
+
+import java.io.InputStream;
+
+import junit.framework.TestCase;
+import org.hibernate.SessionFactory;
+import org.hibernate.cfg.AnnotationConfiguration;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.dialect.Dialect;
+
+/**
+ * Build multiple session factories from the same set of classes
+ * The configuration can be altered overriding the #configure() method
+ *
+ * @author Emmanuel Bernard
+ */
+public abstract class MultipleSFTestCase extends TestCase {
+
+ private static SessionFactory[] sessionFactories;
+ private static AnnotationConfiguration[] cfgs;
+ private static Dialect dialect;
+ private static Class lastTestClass;
+
+ protected abstract int getSFNbrs();
+
+ protected void buildSessionFactories(Class[] classes, String[] packages, String[]
xmlFiles) throws Exception {
+ if (sessionFactories == null) sessionFactories = new SessionFactory[ getSFNbrs() ];
+ if (cfgs == null) cfgs = new AnnotationConfiguration[ getSFNbrs() ];
+ for (SessionFactory sf : sessionFactories ) if ( sf != null ) sf.close();
+ for (int sfIndex = 0 ; sfIndex < getSFNbrs() ; sfIndex++ ) {
+ cfgs[sfIndex] = new AnnotationConfiguration();
+ }
+ configure( cfgs );
+ for (int sfIndex = 0 ; sfIndex < getSFNbrs() ; sfIndex++ ) {
+ try {
+ if ( recreateSchema() ) {
+ cfgs[sfIndex].setProperty( Environment.HBM2DDL_AUTO, "create-drop" );
+ }
+ for ( int i = 0; i < packages.length; i++ ) {
+ cfgs[sfIndex].addPackage( packages[i] );
+ }
+ for ( int i = 0; i < classes.length; i++ ) {
+ cfgs[sfIndex].addAnnotatedClass( classes[i] );
+ }
+ for ( int i = 0; i < xmlFiles.length; i++ ) {
+ InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(
xmlFiles[i] );
+ cfgs[sfIndex].addInputStream( is );
+ }
+ setDialect( Dialect.getDialect() );
+ sessionFactories[sfIndex] = cfgs[sfIndex].buildSessionFactory( /*new
TestInterceptor()*/ );
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ throw e;
+ }
+ }
+ }
+
+ protected void setUp() throws Exception {
+ if ( sessionFactories == null || sessionFactories[0] == null || lastTestClass !=
getClass() ) {
+ buildSessionFactories( getMappings(), getAnnotatedPackages(), getXmlFiles() );
+ lastTestClass = getClass();
+ }
+ }
+
+ protected abstract Class[] getMappings();
+
+ protected String[] getAnnotatedPackages() {
+ return new String[]{};
+ }
+
+ protected String[] getXmlFiles() {
+ return new String[]{};
+ }
+
+ private void setDialect(Dialect dialect) {
+ MultipleSFTestCase.dialect = dialect;
+ }
+
+ protected Dialect getDialect() {
+ return dialect;
+ }
+
+ protected abstract void configure(Configuration[] cfg) ;
+
+ protected boolean recreateSchema() {
+ return true;
+ }
+
+ public static SessionFactory[] getSessionFactories() {
+ return sessionFactories;
+ }
+}
Added:
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/directoryProvider/SnowStorm.java
===================================================================
---
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/directoryProvider/SnowStorm.java
(rev 0)
+++
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/directoryProvider/SnowStorm.java 2007-02-27
02:17:25 UTC (rev 11246)
@@ -0,0 +1,58 @@
+//$Id: $
+package org.hibernate.search.test.directoryProvider;
+
+import java.util.Date;
+import javax.persistence.Id;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Entity;
+
+import org.hibernate.search.annotations.Indexed;
+import org.hibernate.search.annotations.DocumentId;
+import org.hibernate.search.annotations.Field;
+import org.hibernate.search.annotations.Index;
+import org.hibernate.search.annotations.DateBridge;
+import org.hibernate.search.annotations.Resolution;
+
+/**
+ * @author Emmanuel Bernard
+ */
+@Indexed
+@Entity
+public class SnowStorm {
+ @Id
+ @GeneratedValue
+ @DocumentId
+ private Long id;
+
+ @Field(index = Index.UN_TOKENIZED)
+ @DateBridge( resolution = Resolution.DAY )
+ private Date date;
+
+ @Field(index = Index.TOKENIZED)
+ private String location;
+
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Date getDate() {
+ return date;
+ }
+
+ public void setDate(Date date) {
+ this.date = date;
+ }
+
+ public String getLocation() {
+ return location;
+ }
+
+ public void setLocation(String location) {
+ this.location = location;
+ }
+}
Added:
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/master/JMSMasterTest.java
===================================================================
---
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/master/JMSMasterTest.java
(rev 0)
+++
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/master/JMSMasterTest.java 2007-02-27
02:17:25 UTC (rev 11246)
@@ -0,0 +1,152 @@
+//$Id: $
+package org.hibernate.search.test.jms.master;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import javax.jms.ObjectMessage;
+import javax.jms.Queue;
+import javax.jms.QueueConnection;
+import javax.jms.QueueConnectionFactory;
+import javax.jms.QueueSender;
+import javax.jms.QueueSession;
+import javax.naming.InitialContext;
+
+import org.apache.lucene.analysis.StopAnalyzer;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.queryParser.QueryParser;
+import org.apache.lucene.search.Query;
+import org.hibernate.Session;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.search.Environment;
+import org.hibernate.search.FullTextSession;
+import org.hibernate.search.Search;
+import org.hibernate.search.engine.DocumentBuilder;
+import org.hibernate.search.backend.AddWork;
+import org.hibernate.search.backend.Work;
+import org.hibernate.search.backend.impl.jms.JMSBackendQueueProcessorFactory;
+import org.hibernate.search.test.SearchTestCase;
+import org.jboss.deployers.spi.DeploymentException;
+import org.jboss.embedded.Bootstrap;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class JMSMasterTest extends SearchTestCase {
+
+ private Bootstrap bootstrap;
+
+ public void testMessageSending() throws Exception {
+ MyHibernateUtil.sessionFactory = getSessions();
+
+ //create an object wo trigggering indexing
+ Session s = openSession( );
+ s.getTransaction().begin();
+ s.connection().createStatement().executeUpdate(
+ "insert into TShirt_Master(id, logo, size) values( '1', 'JBoss
balls', 'large')"
+ );
+ TShirt ts = (TShirt) s.get(TShirt.class, 1);
+ s.getTransaction().commit();
+ s.close();
+ //create the work queue to send
+ Document doc = new Document();
+ Field field = new Field( DocumentBuilder.CLASS_FIELDNAME, ts.getClass().getName(),
Field.Store.YES, Field.Index.UN_TOKENIZED );
+ doc.add( field );
+ field = new Field("id", "1", Field.Store.YES,
Field.Index.UN_TOKENIZED );
+ doc.add( field );
+ field = new Field("logo", ts.getLogo(), Field.Store.NO, Field.Index.TOKENIZED
);
+ doc.add( field );
+ Work work = new AddWork(ts.getId(), ts.getClass(), doc );
+ List<Work> queue = new ArrayList<Work>();
+ queue.add( work );
+
+ //send the queue
+ InitialContext context = new InitialContext();
+ QueueConnectionFactory factory = (QueueConnectionFactory) context.lookup(
"java:/ConnectionFactory" );
+ Queue jmsQueue = (Queue) context.lookup( "queue/searchtest" );
+ QueueConnection cnn;
+ QueueSender sender;
+ QueueSession session;
+ cnn = factory.createQueueConnection();
+ //TODO make transacted parameterized
+ session = cnn.createQueueSession( false, QueueSession.AUTO_ACKNOWLEDGE );
+
+ ObjectMessage message = session.createObjectMessage();
+ message.setObject( (Serializable) queue );
+
+ sender = session.createSender( jmsQueue );
+ sender.send( message );
+
+ session.close();
+ cnn.close();
+
+ //wait for the message to be processed
+ Thread.sleep( 1000 );
+
+ FullTextSession ftSess = Search.createFullTextSession( openSession( ) );
+ ftSess.getTransaction().begin();
+ QueryParser parser = new QueryParser( "id", new StopAnalyzer() );
+ Query luceneQuery = parser.parse( "logo:jboss" );
+ org.hibernate.Query query = ftSess.createFullTextQuery( luceneQuery );
+ List result = query.list();
+ assertEquals( 1, result.size() );
+ ftSess.delete( result.get( 0 ) );
+ ftSess.getTransaction().commit();
+ ftSess.close();
+ }
+
+ protected void setUp() throws Exception {
+ bootstrap = startupEmbeddedJBoss();
+ try {
+ super.setUp();
+ }
+ catch( RuntimeException e ) {
+ try {
+ shutdownEmbeddedJBoss(bootstrap);
+ }
+ catch( Exception ee ) {
+ //swallow
+ }
+ throw e;
+ }
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ shutdownEmbeddedJBoss(bootstrap);
+ }
+
+ public static Bootstrap startupEmbeddedJBoss() {
+ try {
+ long start = System.currentTimeMillis();
+ Bootstrap bootstrap = new Bootstrap();
+ bootstrap.bootstrap();
+ bootstrap.deployResource( "jars/jms-master.jar" );
+ System.out.println("JBoss Embedded boot time: " +
(System.currentTimeMillis() - start) + " ms");
+ return bootstrap;
+ }
+ catch (DeploymentException e) {
+ throw new RuntimeException( "Failed to bootstrap", e );
+ }
+ }
+
+ public static void shutdownEmbeddedJBoss(Bootstrap bootstrap) {
+ bootstrap.shutdown();
+ }
+
+
+ protected void configure(Configuration cfg) {
+ super.configure( cfg );
+ cfg.setProperty( Environment.WORKER_BACKEND, "lucene" );
+ cfg.setProperty( JMSBackendQueueProcessorFactory.JMS_CONNECTION_FACTORY,
"java:/ConnectionFactory" );
+ cfg.setProperty( JMSBackendQueueProcessorFactory.JMS_QUEUE,
"queue/searchtest" );
+
+ }
+
+ protected Class[] getMappings() {
+ return new Class[] {
+ TShirt.class
+ };
+ }
+}
Added:
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/master/MDBSearchController.java
===================================================================
---
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/master/MDBSearchController.java
(rev 0)
+++
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/master/MDBSearchController.java 2007-02-27
02:17:25 UTC (rev 11246)
@@ -0,0 +1,27 @@
+//$Id: $
+package org.hibernate.search.test.jms.master;
+
+import javax.ejb.MessageDriven;
+import javax.ejb.ActivationConfigProperty;
+import javax.jms.MessageListener;
+
+import org.hibernate.search.backend.impl.jms.AbstractJMSHibernateSearchController;
+import org.hibernate.Session;
+
+/**
+ * @author Emmanuel Bernard
+ */
+@MessageDriven(activationConfig = {
+ @ActivationConfigProperty(propertyName="destinationType",
propertyValue="javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName="destination",
propertyValue="queue/searchtest"),
+ @ActivationConfigProperty(propertyName="DLQMaxResent",
propertyValue="1")
+ } )
+public class MDBSearchController extends AbstractJMSHibernateSearchController implements
MessageListener {
+ protected Session getSession() {
+ return MyHibernateUtil.sessionFactory.openSession( );
+ }
+
+ protected void cleanSessionIfNeeded(Session session) {
+ session.close();
+ }
+}
Added:
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/master/MyHibernateUtil.java
===================================================================
---
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/master/MyHibernateUtil.java
(rev 0)
+++
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/master/MyHibernateUtil.java 2007-02-27
02:17:25 UTC (rev 11246)
@@ -0,0 +1,12 @@
+//$Id: $
+package org.hibernate.search.test.jms.master;
+
+import org.hibernate.SessionFactory;
+
+/**
+ * Don't do it at home ;-)
+ * @author Emmanuel Bernard
+ */
+public class MyHibernateUtil {
+ public static SessionFactory sessionFactory;
+}
Added:
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/master/TShirt.java
===================================================================
---
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/master/TShirt.java
(rev 0)
+++
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/master/TShirt.java 2007-02-27
02:17:25 UTC (rev 11246)
@@ -0,0 +1,52 @@
+//$Id: $
+package org.hibernate.search.test.jms.master;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Table;
+
+import org.hibernate.search.annotations.Indexed;
+import org.hibernate.search.annotations.DocumentId;
+import org.hibernate.search.annotations.Field;
+import org.hibernate.search.annotations.Index;
+
+/**
+ * @author Emmanuel Bernard
+ */
+@Entity
+@Indexed
+@Table(name="TShirt_Master")
+public class TShirt {
+ @Id
+ @DocumentId
+ private int id;
+ @Field(index= Index.TOKENIZED)
+ private String logo;
+ private String size;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getLogo() {
+ return logo;
+ }
+
+ public void setLogo(String logo) {
+ this.logo = logo;
+ }
+
+ public String getSize() {
+ return size;
+ }
+
+ public void setSize(String size) {
+ this.size = size;
+ }
+}
+
Added:
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/slave/JMSSlaveTest.java
===================================================================
---
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/slave/JMSSlaveTest.java
(rev 0)
+++
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/slave/JMSSlaveTest.java 2007-02-27
02:17:25 UTC (rev 11246)
@@ -0,0 +1,116 @@
+//$Id: $
+package org.hibernate.search.test.jms.slave;
+
+import org.jboss.embedded.Bootstrap;
+import org.jboss.deployers.spi.DeploymentException;
+import org.hibernate.search.test.SearchTestCase;
+import org.hibernate.search.Environment;
+import org.hibernate.search.backend.impl.jms.JMSBackendQueueProcessorFactory;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class JMSSlaveTest extends SearchTestCase {
+
+ private Bootstrap bootstrap;
+
+
+ protected void setUp() throws Exception {
+ bootstrap = startupEmbeddedJBoss();
+ try {
+ super.setUp();
+ }
+ catch( RuntimeException e ) {
+ try {
+ shutdownEmbeddedJBoss(bootstrap);
+ }
+ catch( Exception ee ) {
+ //swallow
+ }
+ throw e;
+ }
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ shutdownEmbeddedJBoss(bootstrap);
+ }
+
+ public void testMessageSend() throws Exception {
+ SearchQueueChecker.reset();
+ Session s = openSession();
+ Transaction tx = s.beginTransaction();
+ TShirt ts = new TShirt();
+ ts.setLogo( "Boston" );
+ ts.setSize( "XXL" );
+ TShirt ts2 = new TShirt();
+ ts2.setLogo( "Mapple leaves" );
+ ts2.setSize( "L" );
+ s.persist( ts );
+ s.persist( ts2 );
+ tx.commit();
+ //need to sleep for the message consumption
+ Thread.sleep(500);
+ assertEquals( 1, SearchQueueChecker.queues );
+ assertEquals( 2, SearchQueueChecker.works );
+
+ SearchQueueChecker.reset();
+ s = openSession();
+ tx = s.beginTransaction();
+ ts = (TShirt) s.get( TShirt.class, ts.getId() );
+ ts.setLogo( "Peter pan" );
+ tx.commit();
+ //need to sleep for the message consumption
+ Thread.sleep(500);
+ assertEquals( 1, SearchQueueChecker.queues );
+ assertEquals( 2, SearchQueueChecker.works ); //one update = 2 works
+
+ SearchQueueChecker.reset();
+ s = openSession();
+ tx = s.beginTransaction();
+ s.delete( s.get( TShirt.class, ts.getId() ) );
+ s.delete( s.get( TShirt.class, ts2.getId() ) );
+ tx.commit();
+ //Need to sleep for the message consumption
+ Thread.sleep(500);
+ assertEquals( 1, SearchQueueChecker.queues );
+ assertEquals( 2, SearchQueueChecker.works );
+ s.close();
+ }
+
+ public static Bootstrap startupEmbeddedJBoss() {
+ try {
+ long start = System.currentTimeMillis();
+ Bootstrap bootstrap = new Bootstrap();
+ bootstrap.bootstrap();
+ bootstrap.deployResource( "jars/jms-slave.jar" );
+ System.out.println("JBoss Embedded boot time: " +
(System.currentTimeMillis() - start) + " ms");
+ return bootstrap;
+ }
+ catch (DeploymentException e) {
+ throw new RuntimeException( "Failed to bootstrap", e );
+ }
+ }
+
+ public static void shutdownEmbeddedJBoss(Bootstrap bootstrap) {
+ bootstrap.shutdown();
+ }
+
+
+ protected void configure(Configuration cfg) {
+ super.configure( cfg );
+ cfg.setProperty( Environment.WORKER_BACKEND, "jms" );
+ cfg.setProperty( JMSBackendQueueProcessorFactory.JMS_CONNECTION_FACTORY,
"java:/ConnectionFactory" );
+ cfg.setProperty( JMSBackendQueueProcessorFactory.JMS_QUEUE,
"queue/searchtest" );
+
+ }
+
+ protected Class[] getMappings() {
+ return new Class[]{
+ TShirt.class
+ };
+ }
+}
Added:
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/slave/SearchQueueChecker.java
===================================================================
---
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/slave/SearchQueueChecker.java
(rev 0)
+++
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/slave/SearchQueueChecker.java 2007-02-27
02:17:25 UTC (rev 11246)
@@ -0,0 +1,49 @@
+//$Id: $
+package org.hibernate.search.test.jms.slave;
+
+import java.util.List;
+import javax.jms.MessageListener;
+import javax.jms.Message;
+import javax.jms.ObjectMessage;
+import javax.jms.JMSException;
+import javax.ejb.MessageDriven;
+import javax.ejb.ActivationConfigProperty;
+
+import org.hibernate.search.backend.Work;
+
+/**
+ * @author Emmanuel Bernard
+ */
+@MessageDriven(activationConfig = {
+ @ActivationConfigProperty(propertyName="destinationType",
propertyValue="javax.jms.Queue"),
+ @ActivationConfigProperty(propertyName="destination",
propertyValue="queue/searchtest"),
+ @ActivationConfigProperty(propertyName="DLQMaxResent",
propertyValue="1")
+ } )
+public class SearchQueueChecker implements MessageListener {
+ public static int queues;
+ public static int works;
+
+ public static void reset() {
+ queues = 0;
+ works = 0;
+ }
+
+ public void onMessage(Message message) {
+ if (! (message instanceof ObjectMessage ) ) {
+ return;
+ }
+ ObjectMessage objectMessage = (ObjectMessage) message;
+ List<Work> queue;
+ try {
+ queue = (List<Work>) objectMessage.getObject();
+ }
+ catch (JMSException e) {
+ return;
+ }
+ catch( ClassCastException e ) {
+ return;
+ }
+ queues++;
+ works+=queue.size();
+ }
+}
Added:
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/slave/TShirt.java
===================================================================
---
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/slave/TShirt.java
(rev 0)
+++
branches/Branch_3_2/HibernateExt/search/src/test/org/hibernate/search/test/jms/slave/TShirt.java 2007-02-27
02:17:25 UTC (rev 11246)
@@ -0,0 +1,50 @@
+//$Id: $
+package org.hibernate.search.test.jms.slave;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.GeneratedValue;
+
+import org.hibernate.search.annotations.Indexed;
+import org.hibernate.search.annotations.DocumentId;
+import org.hibernate.search.annotations.Field;
+import org.hibernate.search.annotations.Index;
+
+/**
+ * @author Emmanuel Bernard
+ */
+@Entity
+@Indexed
+public class TShirt {
+ @Id
+ @GeneratedValue
+ @DocumentId
+ private int id;
+ @Field(index= Index.TOKENIZED)
+ private String logo;
+ private String size;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getLogo() {
+ return logo;
+ }
+
+ public void setLogo(String logo) {
+ this.logo = logo;
+ }
+
+ public String getSize() {
+ return size;
+ }
+
+ public void setSize(String size) {
+ this.size = size;
+ }
+}