/**
* Amanuensis, a distributed Lucene Index Writer for Infinispan
*
* Copyright (c) 2011, Tristan Tarrant
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package net.dataforte.infinispan.amanuensis;
import net.dataforte.commons.slf4j.LoggerFactory;
import net.dataforte.infinispan.amanuensis.ops.AddDocumentOperation;
import net.dataforte.infinispan.amanuensis.ops.DeleteDocumentsQueriesOperation;
import net.dataforte.infinispan.amanuensis.ops.DeleteDocumentsTermsOperation;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.Query;
import org.apache.lucene.store.Directory;
import org.slf4j.Logger;
public class AmanuensisIndexWriter {
private static final Logger log = LoggerFactory.make();
private AmanuensisManager manager;
private String directoryId;
private ThreadLocal<IndexOperations> batchOps;
private Directory directory;
public AmanuensisIndexWriter(AmanuensisManager manager, Directory directory) throws IndexerException {
this.manager = manager;
this.directoryId = AmanuensisManager.getUniqueDirectoryIdentifier(directory);
this.directory = directory;
this.batchOps = new ThreadLocal<IndexOperations>();
}
public String getDirectoryId() {
return directoryId;
}
public Directory getDirectory() {
return directory;
}
// IndexWriter methods
public boolean isBatching() {
return batchOps.get() != null;
}
/**
* Put this InfinispanIndexWriter in batch mode: all operations will be
* queued and sent when the {@link AmanuensisIndexWriter#endBatch} method is
* invoked. Note that the batches are local to the current thread, therefore
* each thread may start and end a batch indipendently from the others.
*
* @see AmanuensisIndexWriter#endBatch()
* @see AmanuensisIndexWriter#cancelBatch()
*/
public void startBatch() {
if (isBatching()) {
throw new IllegalStateException("Already in batching mode");
} else {
batchOps.set(new IndexOperations(this.directoryId));
if (log.isDebugEnabled()) {
log.debug("Batching started for index " + directoryId);
}
}
}
/**
* Send all changes in the current batch, started by
* {@link AmanuensisIndexWriter#startBatch()} to the master node for
* indexing
*
* @throws IndexerException
*
* @see AmanuensisIndexWriter#startBatch()
* @see AmanuensisIndexWriter#cancelBatch()
*/
public void endBatch() throws IndexerException {
if (!isBatching()) {
throw new IllegalStateException("Not in batching mode");
} else {
manager.dispatchOperations(batchOps.get());
batchOps.remove();
if (log.isDebugEnabled()) {
log.debug("Batching finished for index " + directoryId);
}
}
}
/**
* Cancels the current batch: all queued changes will be reset and not sent
* to the master
*
* @see AmanuensisIndexWriter#startBatch()
* @see AmanuensisIndexWriter#endBatch()
*/
public void cancelBatch() {
if (!isBatching()) {
throw new IllegalStateException("Not in batching mode");
} else {
batchOps.remove();
if (log.isDebugEnabled()) {
log.debug("Batching cancelled for index " + directoryId);
}
}
}
/**
* Adds a single {@link Document} to the index
*
* @param doc
* @throws IndexerException
*/
public void addDocument(Document doc) throws IndexerException {
dispatch(new AddDocumentOperation(doc));
}
/**
* Adds multiple {@link Document} to the index
*
* @param docs
* @throws IndexerException
*/
public void addDocuments(Document... docs) throws IndexerException {
if (docs.length == 0) {
return;
}
IndexOperation ops[] = new IndexOperation[docs.length];
for (int i = 0; i < ops.length; i++) {
ops[i] = new AddDocumentOperation(docs[i]);
}
dispatch(ops);
}
/**
* Deletes all documents from the index which match the given array of
* {@link Query}
*
* @param queries
* @throws IndexerException
*/
public void deleteDocuments(Query... queries) throws IndexerException {
if (queries.length == 0) {
return;
}
IndexOperation ops[] = new IndexOperation[queries.length];
for (int i = 0; i < queries.length; i++) {
ops[i] = new DeleteDocumentsQueriesOperation(queries[i]);
}
dispatch(ops);
}
/**
* Deletes all documents from the index which match the given array of
* {@link Term}
*
* @param queries
* @throws IndexerException
*/
public void deleteDocuments(Term... terms) throws IndexerException {
if (terms.length == 0) {
return;
}
IndexOperation ops[] = new IndexOperation[terms.length];
for (int i = 0; i < terms.length; i++) {
ops[i] = new DeleteDocumentsTermsOperation(terms[i]);
}
dispatch(ops);
}
// INTERNAL METHODS
private void dispatch(IndexOperation... ops) throws IndexerException {
if (isBatching()) {
batchOps.get().addOperations(ops);
} else {
manager.dispatchOperations(new IndexOperations(this.directoryId, ops));
}
}
}