Author: navssurtani
Date: 2009-03-19 13:06:05 -0400 (Thu, 19 Mar 2009)
New Revision: 7928
Added:
searchable/trunk/src/main/java/org/jboss/cache/search/NodeRemovedTransactionContext.java
searchable/trunk/src/test/java/org/jboss/cache/search/blackbox/IndexingInTransaction.java
Modified:
searchable/trunk/src/main/java/org/jboss/cache/search/SearchableCoreListener.java
Log:
Added NodeRemovedTransactionContext class ... should deal with indexes not being removed
when @NodeRemoved is found
Added:
searchable/trunk/src/main/java/org/jboss/cache/search/NodeRemovedTransactionContext.java
===================================================================
---
searchable/trunk/src/main/java/org/jboss/cache/search/NodeRemovedTransactionContext.java
(rev 0)
+++
searchable/trunk/src/main/java/org/jboss/cache/search/NodeRemovedTransactionContext.java 2009-03-19
17:06:05 UTC (rev 7928)
@@ -0,0 +1,52 @@
+package org.jboss.cache.search;
+
+import org.hibernate.search.backend.TransactionContext;
+import org.jboss.cache.notifications.event.NodeRemovedEvent;
+
+import javax.transaction.Synchronization;
+import javax.transaction.Transaction;
+
+/**
+ * @author Navin Surtani (<a
href="mailto:nsurtani@redhat.com">nsurtani@redhat.com</a>)
+ */
+public class NodeRemovedTransactionContext implements TransactionContext
+{
+
+ NodeRemovedEvent event;
+
+ public NodeRemovedTransactionContext(NodeRemovedEvent event)
+ {
+ if (event == null) throw new NullPointerException("event cannot be
null");
+ this.event = event;
+ }
+
+ public boolean isTransactionInProgress()
+ {
+ return (event.getTransaction() != null);
+ }
+
+ public Object getTransactionIdentifier()
+ {
+ return event.getTransaction();
+ }
+
+ public void registerSynchronization(Synchronization synchronization)
+ {
+ if (synchronization == null) throw new NullPointerException("Synchronization
passed in is null!");
+
+ Transaction transaction = event.getTransaction();
+ if (transaction != null)
+ {
+ try
+ {
+ transaction.registerSynchronization(synchronization);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+
+
+ }
+ }
+}
Modified:
searchable/trunk/src/main/java/org/jboss/cache/search/SearchableCoreListener.java
===================================================================
---
searchable/trunk/src/main/java/org/jboss/cache/search/SearchableCoreListener.java 2009-03-19
15:47:58 UTC (rev 7927)
+++
searchable/trunk/src/main/java/org/jboss/cache/search/SearchableCoreListener.java 2009-03-19
17:06:05 UTC (rev 7928)
@@ -18,7 +18,7 @@
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
- */
+ */
package org.jboss.cache.search;
@@ -28,7 +28,9 @@
import org.hibernate.search.engine.SearchFactoryImplementor;
import org.jboss.cache.notifications.annotation.CacheListener;
import org.jboss.cache.notifications.annotation.NodeModified;
+import org.jboss.cache.notifications.annotation.NodeRemoved;
import org.jboss.cache.notifications.event.NodeModifiedEvent;
+import org.jboss.cache.notifications.event.NodeRemovedEvent;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -36,8 +38,8 @@
/**
* @author Navin Surtani (<a
href="mailto:nsurtani@redhat.com">nsurtani@redhat.com</a>)
- *
- * Listener class for changes made to the cache. This listener makes changes if it is a
{@link org.jboss.cache.Cache} being used.
+ * <p/>
+ * Listener class for changes made to the cache. This listener makes changes if
it is a {@link org.jboss.cache.Cache} being used.
*/
@CacheListener
public class SearchableCoreListener
@@ -47,7 +49,7 @@
public SearchableCoreListener(SearchFactoryImplementor searchFactory)
{
-
+
this.searchFactory = searchFactory;
}
@@ -57,7 +59,7 @@
* @param event that has occured - or a node that has been changed. {@link
org.jboss.cache.notifications.event.NodeModifiedEvent}
* @throws InvalidKeyException if an invalid key is passed in.
*/
-
+
@NodeModified
public void updateLuceneIndexes(NodeModifiedEvent event) throws InvalidKeyException
{
@@ -80,11 +82,47 @@
}
}
- /**
+
+ @NodeRemoved
+ protected void handleNodeRemoved(NodeRemovedEvent event) throws InvalidKeyException
+ {
+
+ if (log.isDebugEnabled()) log.debug("Entered the SCL. @NodeRemoved annotation
found");
+ if (!event.isPre())
+ {
+ // Directly going to handle the deletion of data.
+ Map dataMap = event.getData();
+ if (log.isTraceEnabled()) log.trace("Called event.getData() and saved to a
Map");
+
+
+ TransactionContext ctx = new NodeRemovedTransactionContext(event);
+
+ for (Object key : dataMap.keySet())
+ {
+ CacheEntityId cacheEntityId = new CacheEntityId(event.getFqn(), (String)
key);
+ if (log.isTraceEnabled()) log.trace("Created new CacheEntityId");
+
+ String fqnString = cacheEntityId.getFqn().toString(); // Vars for logging
+ String keyString = (String) key;
+
+
+ searchFactory.getWorker().performWork(new Work(dataMap.get(key),
cacheEntityId.getDocumentId(), WorkType.DELETE), ctx);
+ searchFactory.getWorker().performWork(new Work(dataMap.get(key),
cacheEntityId.getDocumentId(), WorkType.ADD), ctx);
+
+
+ if (log.isTraceEnabled())
+ {
+ log.debug("Added your object into Lucene with Fqn " + fqnString
+ " and key " + keyString);
+ }
+ }
+ }
+ }
+
+ /**
* If the modification type is PUT_MAP or PUT_DATA then this method will be called.
* Takes in the event as a parameter
*
- * @param event that has occured - or a node that has been changed. {@link
org.jboss.cache.notifications.event.NodeModifiedEvent}
+ * @param event that has occured - or a node that has been changed. {@link
org.jboss.cache.notifications.event.NodeModifiedEvent}
* @param searchFactory - a SearchFactoryImpl instance.
* @throws InvalidKeyException
*/
@@ -122,12 +160,11 @@
}
-
/**
* If the modification type is DELETE_DATA then this method will be called.
* Takes in the event as a parameter
*
- * @param event that has occured - or a node that has been changed. {@link
org.jboss.cache.notifications.event.NodeModifiedEvent}
+ * @param event that has occured - or a node that has been changed. {@link
org.jboss.cache.notifications.event.NodeModifiedEvent}
* @param searchFactory - a SearchFactoryImpl instance.
* @throws InvalidKeyException
*/
@@ -146,7 +183,8 @@
searchFactory.getWorker().performWork(new Work(dataMap.get(key),
cacheEntityId.getDocumentId(), WorkType.DELETE), ctx);
- if (log.isTraceEnabled()) log.trace("Deleted your object from Lucene with
Fqn " + fqnString + " and key " + keyString);
+ if (log.isTraceEnabled())
+ log.trace("Deleted your object from Lucene with Fqn " + fqnString +
" and key " + keyString);
}
Added:
searchable/trunk/src/test/java/org/jboss/cache/search/blackbox/IndexingInTransaction.java
===================================================================
---
searchable/trunk/src/test/java/org/jboss/cache/search/blackbox/IndexingInTransaction.java
(rev 0)
+++
searchable/trunk/src/test/java/org/jboss/cache/search/blackbox/IndexingInTransaction.java 2009-03-19
17:06:05 UTC (rev 7928)
@@ -0,0 +1,194 @@
+package org.jboss.cache.search.blackbox;
+
+import org.hibernate.search.annotations.Field;
+import org.hibernate.search.annotations.ProvidedId;
+import org.hibernate.search.annotations.Indexed;
+import org.hibernate.search.annotations.Store;
+import org.jboss.cache.*;
+import org.jboss.cache.loader.jdbm.JdbmCacheLoaderConfig;
+import org.jboss.cache.config.Configuration;
+import org.jboss.cache.config.CacheLoaderConfig;
+import org.jboss.cache.search.SearchableCacheFactory;
+import org.jboss.cache.search.SearchableCache;
+import org.testng.annotations.Test;
+import org.testng.annotations.BeforeMethod;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.search.BooleanClause;
+import org.apache.lucene.index.Term;
+
+import static org.testng.AssertJUnit.*;
+
+import java.util.Properties;
+import java.util.List;
+import java.io.Serializable;
+
+@Test(groups = {"unit"}, sequential = true)
+public class IndexingInTransaction
+{
+
+ private static final Fqn fname = Fqn.fromString("blah");
+
+ private Cache coreCache;
+
+ private SearchableCache searchableCache;
+
+ Node node;
+
+ public IndexingInTransaction()
+ {
+ init();
+ }
+
+ @BeforeMethod
+ public void init()
+ {
+ CacheFactory factory = new DefaultCacheFactory();
+ Configuration c = new Configuration();
+ c.setInvocationBatchingEnabled(true);
+
+ CacheLoaderConfig clc = new CacheLoaderConfig();
+
+ JdbmCacheLoaderConfig jclc = new JdbmCacheLoaderConfig();
+ jclc.setAsync(false);
+ jclc.setFetchPersistentState(false);
+ jclc.setIgnoreModifications(false);
+ jclc.setPurgeOnStartup(true);
+ jclc.setLocation("/tmp/c1");
+
+ clc.addIndividualCacheLoaderConfig(jclc);
+ c.setCacheLoaderConfig(clc);
+
+ coreCache = factory.createCache(c, false);
+
+ SearchableCacheFactory f = new SearchableCacheFactory();
+ Properties p = new Properties();
+ p.put("hibernate.search.default.indexBase", "/tmp/c1idx");
+ p.put("hibernate.search.worker.batch_size", "1");
+ searchableCache = f.createSearchableCache(coreCache, p, Entity.class);
+ searchableCache.create();
+ searchableCache.start();
+ node = searchableCache.getRoot().addChild(fname);
+ }
+
+ @Test
+ public void testPutEntitiesWithoutTransaction()
+ {
+ for (int i = 1; i <= 10; i++)
+ {
+ Entity e = getEntity(i);
+ System.out.println("caching: " + e);
+ Node c = node.addChild(Fqn.fromString(e.getName()));
+ c.put("" + e.getId(), e);
+ }
+ assertFalse(searchableCache.createQuery(
+ Entity.searchByName("Name5")).list().isEmpty());
+ }
+
+ @Test
+ public void testPutEntitiesWithTransaction() throws Exception
+ {
+ ((CacheSPI) (coreCache)).getTransactionManager().begin();
+ for (int i = 15; i <= 15; i++)
+ {
+ Entity e = getEntity(i);
+ System.out.println("caching: " + e);
+ Node c = node.addChild(Fqn.fromString(e.getName()));
+ c.put("" + e.getId(), e);
+ }
+ ((CacheSPI) (coreCache)).getTransactionManager().commit();
+
+ assertFalse("there should be record for the name15",
+ searchableCache.createQuery(
+ Entity.searchByName("Name15")).list().isEmpty());
+
+ node.removeChild(Fqn.fromString("Name15"));
+
+ List l =
searchableCache.createQuery(Entity.searchByName("Name15")).list();
+
+ // bug: collection is not empty - there is null as there are inconsistencies in the
indexes
+ assertTrue("there should be no record found", l.isEmpty());
+
+ }
+
+ Entity getEntity(long id)
+ {
+ return new Entity(id, "Name" + id, "Surname" + id, true);
+ }
+
+// public static void main(String[] args) {
+// IndexingInTransaction stb = new IndexingInTransaction();
+// stb.init();
+// }
+
+}
+
+@ProvidedId
+@Indexed
+class Entity implements Serializable
+{
+
+ public static final String IDX_NAME = "name";
+ public static final String IDX_SURNAME = "surname";
+
+ private long id;
+
+ @Field(store = Store.YES)
+ private String name;
+
+ @Field(store = Store.YES)
+ private String surname;
+
+ private boolean dead;
+
+ Entity(long id, String name, String surname, boolean dead)
+ {
+ this.id = id;
+ this.name = name;
+ this.surname = surname;
+ this.dead = dead;
+ }
+
+ public long getId()
+ {
+ return id;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public String getSurname()
+ {
+ return surname;
+ }
+
+ public boolean isDead()
+ {
+ return dead;
+ }
+
+ public static Query searchByName(String name)
+ {
+ BooleanQuery query = new BooleanQuery();
+ query.add(new TermQuery(
+ new Term(Entity.IDX_NAME,
+ name.toLowerCase())),
+ BooleanClause.Occur.MUST);
+ return query;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "Entity{" +
+ "id=" + id +
+ ", name='" + name + '\'' +
+ ", surname='" + surname + '\'' +
+ ", dead=" + dead +
+ '}';
+ }
+
+}
\ No newline at end of file