package ru.hflabs.rcd.lucene.transaction;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.ReflectionUtils;
import ru.hflabs.rcd.lucene.IndexWriterAccessor;
import ru.hflabs.util.io.IOUtils;
import java.io.IOException;
/**
* Класс <class>TransactionalIndexWriterAccessor</class> реализует сервис доступа к транзакционному индексу записи
*
* @author Nazin Alexander
* @see org.springframework.transaction.annotation.Transactional
*/
public class TransactionalIndexWriterAccessor extends TransactionSynchronizationAdapter implements IndexWriterAccessor {
/** Конфигурация сервис записи */
private IndexWriterConfig indexWriterConfig;
public void setIndexWriterConfig(IndexWriterConfig indexWriterConfig) {
this.indexWriterConfig = indexWriterConfig;
}
/**
* Создает и возвращает сервис записи в индекс
*
* @param directory директория индекса
* @return Возвращает сервис записи в индекс
*/
private IndexWriter createIndexWriter(Directory directory) throws IOException {
return new IndexWriter(directory, indexWriterConfig.clone());
}
@Override
public IndexWriter retrieveWriter(Directory directory) throws IOException {
if (TransactionSynchronizationManager.isSynchronizationActive()) {
// Получаем адаптер синхронизации из менеджера
IndexWriterTransactionSynchronization synchronization = (IndexWriterTransactionSynchronization) TransactionSynchronizationManager.getResource(directory);
if (synchronization == null) {
synchronization = new IndexWriterTransactionSynchronization(new IndexWriter(directory, indexWriterConfig.clone()));
TransactionSynchronizationManager.bindResource(directory, synchronization);
}
// Выполняем перерегистрацию адаптера
TransactionSynchronizationManager.registerSynchronization(synchronization);
// Возвращаем актуальный сервис записи
return synchronization.getWriter();
} else {
return createIndexWriter(directory);
}
}
@Override
public void commitWriter(IndexWriter writer, int changeCount) throws IOException {
if (!TransactionSynchronizationManager.isSynchronizationActive()) {
try {
writer.commit();
} finally {
IOUtils.closeQuietly(writer);
}
}
}
@Override
public void rollbackWriter(IndexWriter writer) throws IOException {
if (!TransactionSynchronizationManager.isSynchronizationActive()) {
try {
writer.rollback();
} finally {
IOUtils.closeQuietly(writer);
}
}
}
/**
* Класс <class>IndexWriterTransactionSynchronization</class> реализует адаптер синхронизации транзакций с сервисом записи в индекс
*
* @author Nazin Alexander
*/
private class IndexWriterTransactionSynchronization extends TransactionSynchronizationAdapter {
/** Сервис записи в индекс */
private IndexWriter writer;
private IndexWriterTransactionSynchronization(IndexWriter writer) {
this.writer = writer;
}
public IndexWriter getWriter() {
return writer;
}
@Override
public void beforeCommit(boolean readOnly) {
if (!readOnly) {
try {
writer.prepareCommit();
} catch (Exception ex) {
ReflectionUtils.rethrowRuntimeException(ex);
}
}
}
@Override
public void afterCommit() {
try {
writer.commit();
} catch (Exception ex) {
ReflectionUtils.rethrowRuntimeException(ex);
}
}
@Override
public void afterCompletion(int status) {
try {
if (status != STATUS_COMMITTED) {
writer.rollback();
} else {
writer.close(false);
}
} catch (Throwable th) {
ReflectionUtils.rethrowRuntimeException(th);
} finally {
TransactionSynchronizationManager.unbindResource(writer.getDirectory());
writer = null;
}
}
}
}