///*
// * Copyright (C) 2005-2006 Alfresco, Inc.
// *
// * Licensed under the Mozilla Public License version 1.1
// * with a permitted attribution clause. You may obtain a
// * copy of the License at
// *
// * http://www.alfresco.org/legal/license.txt
// *
// * Unless required by applicable law or agreed to in writing,
// * software distributed under the License is distributed on an
// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// * either express or implied. See the License for the specific
// * language governing permissions and limitations under the
// * License.
// */
//package org.alfresco.repo.node.index;
//
//import java.util.ArrayList;
//import java.util.List;
//
//import org.alfresco.error.AlfrescoRuntimeException;
//import org.alfresco.model.ContentModel;
//import org.alfresco.repo.domain.NodeStatus;
//import org.alfresco.repo.search.Indexer;
//import org.alfresco.repo.search.impl.lucene.LuceneIndexerImpl;
//import org.alfresco.repo.search.impl.lucene.fts.FullTextSearchIndexer;
//import org.alfresco.repo.transaction.TransactionUtil;
//import org.alfresco.repo.transaction.TransactionUtil.TransactionWork;
//import org.alfresco.service.cmr.repository.ChildAssociationRef;
//import org.alfresco.service.cmr.repository.NodeRef;
//import org.alfresco.service.cmr.repository.NodeService;
//import org.alfresco.service.cmr.repository.StoreRef;
//import org.alfresco.service.cmr.search.ResultSet;
//import org.alfresco.service.cmr.search.SearchParameters;
//import org.alfresco.service.cmr.search.SearchService;
//import org.alfresco.service.transaction.TransactionService;
//import org.apache.commons.logging.Log;
//import org.apache.commons.logging.LogFactory;
//import org.hibernate.CacheMode;
//import org.hibernate.Query;
//import org.hibernate.Session;
//import org.springframework.orm.hibernate3.HibernateCallback;
//import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
//
///**
// * Ensures that the FTS indexing picks up on any outstanding documents that
// * require indexing.
// *
// * This component must be used as a singleton (one per VM) and may only be
// * called to reindex once. It will start a thread that processes all available
// * transactions and keeps checking to ensure that the index is up to date with
// * the latest database changes.
// *
// * The following points are important:
// *
// *
// * By default, the Hibernate L2 cache is used during processing.
// * This can be disabled by either disabling the L2 cache globally
// * for the server (not recommended) or by setting the
// * {@link #setL2CacheMode(String) l2CacheMode} property. If the
// * database is static then the L2 cache usage can be set to use
// * the NORMAL mode. REFRESH should be
// * used where the server will still be accessed from some clients
// * despite the database changing. NORMAL can be used
// * in the case of the caches being clustered, i.e. the caches will
// * not be out of date w.r.t. the database.
// *
// *
// * This process should only be used continuously where the index
// * transactions are following the database transactions. Use the
// * {@link #setRunContinuously(boolean) runContinuously} property
// * to change this behaviour.
// *
// *
// *
// * @author Derek Hulley
// */
//public class MissingContentReindexComponent extends HibernateDaoSupport implements IndexRecovery
//{
// public static final String QUERY_GET_NEXT_CHANGE_TXN_IDS = "node.GetNextChangeTxnIds";
// public static final String QUERY_GET_CHANGED_NODE_STATUSES = "node.GetChangedNodeStatuses";
// public static final String QUERY_GET_DELETED_NODE_STATUSES = "node.GetDeletedNodeStatuses";
// public static final String QUERY_GET_CHANGED_NODE_STATUSES_COUNT = "node.GetChangedNodeStatusesCount";
//
// private static final String START_TXN_ID = "000";
//
// private static Log logger = LogFactory.getLog(FullIndexRecoveryComponent.class);
//
// /** ensures that this process is kicked off once per VM */
// private static boolean started = false;
// /** The current transaction ID being processed */
// private static String currentTxnId = START_TXN_ID;
// /** kept to notify the thread that it should quite */
// private boolean killThread = false;
//
// /** provides transactions to atomically index each missed transaction */
// private TransactionService transactionService;
// /** the component to index the node hierarchy */
// private Indexer indexer;
// /** the FTS indexer that we will prompt to pick up on any un-indexed text */
// private FullTextSearchIndexer ftsIndexer;
// /** the component providing searches of the indexed nodes */
// private SearchService searcher;
// /** the component giving direct access to node instances */
// private NodeService nodeService;
// /** set this to run the index recovery component */
// private boolean executeFullRecovery;
// /** set this on to keep checking for new transactions and never stop */
// private boolean runContinuously;
// /** set the time to wait between checking indexes */
// private long waitTime;
// /** controls how the L2 cache is used */
// private CacheMode l2CacheMode;
//
// /**
// * @return Returns the ID of the current (or last) transaction processed
// */
// public static String getCurrentTransactionId()
// {
// return currentTxnId;
// }
//
// public FullIndexRecoveryComponent()
// {
// this.killThread = false;
// this.executeFullRecovery = false;
// this.runContinuously = false;
// this.waitTime = 1000L;
// this.l2CacheMode = CacheMode.REFRESH;
//
// // ensure that we kill the thread when the VM is shutting down
// Runnable shutdownRunnable = new Runnable()
// {
// public void run()
// {
// killThread = true;
// };
// };
// Thread shutdownThread = new Thread(shutdownRunnable);
// Runtime.getRuntime().addShutdownHook(shutdownThread);
// }
//
// /**
// * @return Returns true if the component has already been started
// */
// public static boolean isStarted()
// {
// return started;
// }
//
// /**
// * @param transactionService provide transactions to index each missed transaction
// */
// public void setTransactionService(TransactionService transactionService)
// {
// this.transactionService = transactionService;
// }
//
// /**
// * @param indexer the indexer that will be index
// */
// public void setIndexer(Indexer indexer)
// {
// this.indexer = indexer;
// }
//
// /**
// * @param ftsIndexer the FTS background indexer
// */
// public void setFtsIndexer(FullTextSearchIndexer ftsIndexer)
// {
// this.ftsIndexer = ftsIndexer;
// }
//
// /**
// * @param searcher component providing index searches
// */
// public void setSearcher(SearchService searcher)
// {
// this.searcher = searcher;
// }
//
// /**
// * @param nodeService provides information about nodes for indexing
// */
// public void setNodeService(NodeService nodeService)
// {
// this.nodeService = nodeService;
// }
//
// /**
// * Set this to true to initiate the full index recovery.
// *
// * This used to default to true but is now false. Set this
// * if the potentially long-running process of checking and fixing the
// * indexes must be started.
// *
// * @param executeFullRecovery
// */
// public void setExecuteFullRecovery(boolean executeFullRecovery)
// {
// this.executeFullRecovery = executeFullRecovery;
// }
//
// /**
// * Set this to ensure that the process continuously checks for new transactions.
// * If not, it will permanently terminate once it catches up with the current
// * transactions.
// *
// * @param runContinuously true to never cease looking for new transactions
// */
// public void setRunContinuously(boolean runContinuously)
// {
// this.runContinuously = runContinuously;
// }
//
// /**
// * Set the time to wait between checking for new transaction changes in the database.
// *
// * @param waitTime the time to wait in milliseconds
// */
// public void setWaitTime(long waitTime)
// {
// this.waitTime = waitTime;
// }
//
// /**
// * Set the hibernate cache mode by name
// *
// * @see org.hibernate.CacheMode
// */
// public void setL2CacheMode(String l2CacheModeStr)
// {
// if (l2CacheModeStr.equals("GET"))
// {
// l2CacheMode = CacheMode.GET;
// }
// else if (l2CacheModeStr.equals("IGNORE"))
// {
// l2CacheMode = CacheMode.IGNORE;
// }
// else if (l2CacheModeStr.equals("NORMAL"))
// {
// l2CacheMode = CacheMode.NORMAL;
// }
// else if (l2CacheModeStr.equals("PUT"))
// {
// l2CacheMode = CacheMode.PUT;
// }
// else if (l2CacheModeStr.equals("REFRESH"))
// {
// l2CacheMode = CacheMode.REFRESH;
// }
// else
// {
// throw new IllegalArgumentException("Unrecognised Hibernate L2 cache mode: " + l2CacheModeStr);
// }
// }
//
// /**
// * Ensure that the index is up to date with the current state of the persistence layer.
// * The full list of unique transaction change IDs is retrieved and used to detect
// * which are not present in the index. All the node changes and deletions for the
// * remaining transactions are then indexed.
// */
// public synchronized void reindex()
// {
// if (FullIndexRecoveryComponent.started)
// {
// throw new AlfrescoRuntimeException
// ("Only one FullIndexRecoveryComponent may be used per VM and it may only be called once");
// }
//
// // ensure that we don't redo this work
// FullIndexRecoveryComponent.started = true;
//
// // work to mark the stores for full text reindexing
// TransactionWork