/* Index ECM Engine - A system for managing the capture (when created
* or received), classification (cataloguing), storage, retrieval,
* revision, sharing, reuse and disposition of documents.
*
* Copyright (C) 2008 Regione Piemonte
* Copyright (C) 2008 Provincia di Torino
* Copyright (C) 2008 Comune di Torino
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2,
* or (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
package it.doqui.index.ecmengine.business.personalization.multirepository.index.lucene;
import it.doqui.index.ecmengine.business.personalization.multirepository.util.EcmEngineMultirepositoryConstants;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import org.alfresco.repo.search.IndexerException;
import org.alfresco.repo.search.impl.lucene.LuceneAnalyser;
import org.alfresco.repo.search.impl.lucene.LuceneConfig;
import org.alfresco.repo.search.impl.lucene.LuceneIndexException;
import org.alfresco.repo.search.impl.lucene.LuceneIndexer;
import org.alfresco.repo.search.impl.lucene.index.IndexInfo;
import org.alfresco.repo.search.impl.lucene.index.TransactionStatus;
import org.alfresco.repo.search.impl.lucene.index.IndexInfo.LockWork;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.apache.log4j.Logger;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.search.IndexSearcher;
public abstract class RepositoryAwareLuceneBase {
private static Logger s_logger = Logger.getLogger(EcmEngineMultirepositoryConstants.MULTIREPOSITORY_INDEX_LOG_CATEGORY);
private IndexInfo indexInfo;
/** The identifier for the store. */
protected StoreRef store;
/** The identifier for the repository. */
protected String repoId;
/** The identifier for the delta. */
protected String deltaId;
/** The Lucene configuration options. */
private LuceneConfig config;
/** The dictionary service. */
private DictionaryService dictionaryService;
/** The status of the transaction. */
private TransactionStatus status = TransactionStatus.UNKNOWN;
protected IndexInfoProxyServiceInterface service;
protected IndexInfoProxyServiceInterface serviceTC;
protected IndexInfoProxyServiceInterface serviceNoTC;
/**
* Initialize the configuration elements of the Lucene store indexers and searchers.
*
* @param store
* @param deltaId
* @throws IOException
*/
protected void initialise(StoreRef store, String deltaId, String repository) throws LuceneIndexException {
this.store = store;
this.deltaId = deltaId;
// XXX: tengo traccia del repository associato all'indexer
this.repoId = repository;
final String basePath = getBasePath();
if(s_logger.isDebugEnabled()){
s_logger.debug("[RepositoryAwareLuceneBase::initialise] " + "Repository '" + repository + "' -- Initializing Lucene with root: " + basePath);
}
final File baseDir = new File(basePath);
indexInfo = IndexInfo.getIndexInfo(baseDir, config);
if(s_logger.isDebugEnabled()){
s_logger.debug("[RepositoryAwareLuceneBase::initialise] " + "Repository '" + repository + "' -- Got IndexInfo: " + indexInfo + " [Cleaner: " + indexInfo.isEnableCleanerThread() +" - Merger: " +indexInfo.isEnableMerger() + "]");
}
// MB: Inizializza le IndexInfoProxy sia TC che NON TC
// Ci serve per evitare che gli oggetti IndexInfoProxyService, terracottati, vengano usati con degli oggetti a null
initIndexInfoProxyService();
try {
if (deltaId != null) {
// indexInfo.setStatus(deltaId, TransactionStatus.ACTIVE, null, null);
//MB: modificato in modo da usare il setStatus che memorizza lo stato del delta
//service.setStatus(deltaId, getRepoStorePath(), TransactionStatus.ACTIVE);
setStatus(TransactionStatus.ACTIVE);
}
} catch (IOException e) {
throw new IndexerException("Failed to set delta as active.");
}
}
/**
* Metodo per creare il Proxy per Index Info
*/
protected void initIndexInfoProxyService() {
s_logger.debug("[RepositoryAwareLuceneBase::initIndexInfoProxyService] creating indexInfoProxyService with deltaId :" + deltaId);
if (this.service == null) {
s_logger.debug("[RepositoryAwareLuceneBase::initIndexInfoProxyService] creating indexInfoProxyService");
this.serviceTC = new IndexInfoProxyService();
s_logger.debug("[RepositoryAwareLuceneBase::initIndexInfoProxyService] creating indexInfoProxyServiceNoTC");
this.serviceNoTC = new IndexInfoProxyServiceNoTC();
}
serviceTC.init(dictionaryService, config, getRepoStorePath());
serviceNoTC.init(dictionaryService, config, getRepoStorePath());
if( isCaller() ){
service=serviceTC;
} else {
service=serviceNoTC;
}
}
private boolean isCaller(){
Throwable ex = new Throwable();
boolean useTC=true;
// Get the list of StackTraceElements from the throwable.
StackTraceElement[] stackElements = ex.getStackTrace();
String buffer="";
for (int lcv=0;lcv<stackElements.length;lcv++) {
String className = stackElements[lcv].getClassName();
if( className.indexOf("IndexRecoveryJob" )!=-1 || // Processo di recover degli indici
className.indexOf("EcmEngineStartup" )!=-1 || // Processo di partenza di check dell'ambiente
className.indexOf("TenantAdminJob" )!=-1 || // Processo di creazione dei tenant. Index verra' allineato in modo asincrono
className.indexOf("CustomModelActivationJob" )!=-1 ){ // Processo di allineamento dei custom model. Index verra' allineato in modo asincrono
useTC=false;
} else if(className.indexOf("doqui" )!=-1 || // Loggo le classi doqui
className.indexOf("alfresco")!=-1 ){ // Loggo le classi alfresco
if(s_logger.isDebugEnabled()){
String method = stackElements[lcv].getMethodName();
String linenumber = ""+stackElements[lcv].getLineNumber();
buffer+=( "ST_REPOAWARE["+lcv+"]: "+className+"."+method+"():"+linenumber+"\n");
}
}
}
if( useTC ){
if(s_logger.isDebugEnabled()){
s_logger.debug("\n"+buffer+"\n");
}
}
return useTC;
}
/**
* Utility method to find the path to the base index.
*
* @return The base path.
*/
private String getBasePath() {
if (config.getIndexRootLocation() == null) {
throw new IndexerException("No configuration for index location");
}
String basePath = config.getIndexRootLocation() + File.separator + getRepoStorePath();
return basePath;
}
protected String getRepoStorePath() {
return repoId + File.separator + store.getProtocol() + File.separator + store.getIdentifier() + File.separator;
}
/**
* Get the repository ID.
*
* @return The repository ID.
*/
public String getRepository() {
return this.repoId;
}
/**
* Get a searcher for the main index. TODO: Split out support for the main index. We really only need this if we want to search over the changing
* index before it is committed.
*
* @return The searcher.
* @throws IOException
*/
protected IndexSearcher getSearcher() throws LuceneIndexException {
initIndexInfoProxyService();
try {
if(s_logger.isDebugEnabled()){
s_logger.debug("[RepositoryAwareLuceneBase::getSearcher] " + "Repository '" + getRepository() + "' -- " + "Creating IndexSearcher from main IndexReader.");
}
// return new RepositoryAwareClosingIndexSearcher(indexInfo.getMainIndexReferenceCountingReadOnlyIndexReader());
return new RepositoryAwareClosingIndexSearcher(service.getReader(getRepoStorePath()));
} catch (IOException e) {
s_logger.error("[RepositoryAwareLuceneBase::getSearcher] " + "Repository '" + getRepository() + "' -- Input/Output error!", e);
throw new LuceneIndexException("Failed to open IndexSearcher for path: " + getBasePath(), e);
}
}
protected RepositoryAwareClosingIndexSearcher getSearcher(LuceneIndexer luceneIndexer) throws LuceneIndexException {
initIndexInfoProxyService();
// If we know the delta id we should do better
try {
if (luceneIndexer == null) {
if(s_logger.isDebugEnabled()){
s_logger.debug("[RepositoryAwareLuceneBase::getSearcher] Repository '" + getRepository() + "' -- " + "LuceneIndexer null. Creating IndexSearcher from main IndexReader.");
}
// return new RepositoryAwareClosingIndexSearcher(indexInfo.getMainIndexReferenceCountingReadOnlyIndexReader());
return new RepositoryAwareClosingIndexSearcher(service.getReader(getRepoStorePath()));
} else {
// TODO: Create appropriate reader that lies about deletions
// from the first
luceneIndexer.flushPending();
if(s_logger.isDebugEnabled()){
s_logger.debug("[RepositoryAwareLuceneBase::getSearcher] Repository '" + getRepository() + "' -- " + "LuceneIndexer flushed. Creating IndexSearcher from main IndexReader.");
}
// return new RepositoryAwareClosingIndexSearcher(indexInfo.getMainIndexReferenceCountingReadOnlyIndexReader(deltaId, luceneIndexer.getDeletions(), luceneIndexer.getDeleteOnlyNodes()));
Set<String> deletions = new HashSet<String>();
deletions.addAll(luceneIndexer.getDeletions());
return new RepositoryAwareClosingIndexSearcher(service.getMainIndexReferenceCountingReadOnlyIndexReader(deltaId, getRepoStorePath(), deletions, luceneIndexer.getDeleteOnlyNodes()));
}
} catch (IOException e) {
s_logger.error("[RepositoryAwareLuceneBase::getSearcher] " + "Repository '" + getRepository() + "' -- Input/Output error!", e);
throw new LuceneIndexException("Failed to open RepositoryAwareClosingIndexSearcher for path: " + getBasePath(), e);
}
}
/**
* Get a reader for the on file portion of the delta.
*
* @return The index reader.
* @throws IOException
*/
// protected IndexReader getDeltaReader() throws LuceneIndexException, IOException {
// return indexInfo.getDeltaIndexReader(deltaId);
// }
/**
* Close the on file reader for the delta if it is open.
*
* @throws IOException
*/
// protected void closeDeltaReader() throws LuceneIndexException, IOException {
// indexInfo.closeDeltaIndexReader(deltaId);
// }
/**
* Get the on file writer for the delta.
*
* @return The writer for the delta.
* @throws IOException
*/
// protected IndexWriter getDeltaWriter() throws LuceneIndexException, IOException {
// return indexInfo.getDeltaIndexWriter(deltaId, new LuceneAnalyser(dictionaryService, config.getDefaultMLIndexAnalysisMode()));
// }
/**
* Close the on disk delta writer.
*
* @throws IOException
*/
// protected void closeDeltaWriter() throws LuceneIndexException, IOException {
// indexInfo.closeDeltaIndexWriter(deltaId);
// }
//
/**
* Save the in memory delta to the disk, make sure there is nothing held in memory.
*
* @throws IOException
*/
protected void saveDelta() throws LuceneIndexException, IOException {
// Only one should exist so we do not need error trapping to execute the
// other
service.saveDelta(deltaId, getRepoStorePath());
}
protected void setInfo(long docs, Set<String> deletions, boolean deleteNodesOnly) throws IOException {
service.setPreparedState(deltaId,getRepoStorePath(), deletions, docs, deleteNodesOnly);
// indexInfo.setPreparedState(deltaId, deletions, docs, deleteNodesOnly);
}
protected void setStatus(TransactionStatus status) throws IOException {
// indexInfo.setStatus(deltaId, status, null, null);
service.setStatus(deltaId, getRepoStorePath(), status);
this.status = status;
}
protected TransactionStatus getStatus() {
return status;
}
// protected IndexReader getReader() throws LuceneIndexException, IOException {
// return indexInfo.getMainIndexReferenceCountingReadOnlyIndexReader();
// }
/**
* Set the dictionary service
*
* @param dictionaryService
*/
public void setDictionaryService(DictionaryService dictionaryService) {
if (serviceTC != null) {
this.serviceTC.setDictionaryService(dictionaryService);
}
if (serviceNoTC != null) {
this.serviceNoTC.setDictionaryService(dictionaryService);
}
this.dictionaryService = dictionaryService;
}
/**
* Get the dictionary service.
*
* @return The dictionary service.
*/
public DictionaryService getDictionaryService() {
return dictionaryService;
}
/**
* Set the Lucene configuration options.
*
* @param config The Lucene configuration options.
*/
public void setLuceneConfig(LuceneConfig config) {
this.config = config;
}
/**
* Get the Lucene configuration options.
*
* @return The configuration options object.
*/
public LuceneConfig getLuceneConfig() {
return config;
}
/**
* Get the ID for the delta we are working with.
*
* @return The ID.
*/
public String getDeltaId() {
return deltaId;
}
/**
* Execute actions while holding the write lock oin the index
*
* @param <R>
* @param lockWork The work to do with write lock.
* @return The result returned by the action.
*/
public <R> R doWithWriteLock(LockWork<R> lockWork) {
return indexInfo.doWithWriteLock(lockWork);
}
}