/*
* eXist Open Source Native XML Database
* Copyright (C) 2001-07 The eXist Project
* http://exist-db.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2
* of the License, 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* $Id$
*/
package org.exist.indexing;
import org.apache.log4j.Logger;
import org.exist.backup.RawDataBackup;
import org.exist.storage.BrokerPool;
import org.exist.storage.DBBroker;
import org.exist.storage.btree.DBException;
import org.exist.util.Configuration;
import org.exist.util.DatabaseConfigurationException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* Manages all custom indexes registered with the database instance.
*/
public class IndexManager {
private final static Logger LOG = Logger.getLogger(IndexManager.class);
public static final String CONFIGURATION_ELEMENT_NAME = "modules";
public static final String CONFIGURATION_MODULE_ELEMENT_NAME = "module";
public static final String INDEXER_MODULES_CLASS_ATTRIBUTE = "class";
public static final String INDEXER_MODULES_ID_ATTRIBUTE = "id";
public final static String PROPERTY_INDEXER_MODULES = "indexer.modules";
private BrokerPool pool;
private Map indexers = new HashMap();
/**
* Constructs a new IndexManager and registers the indexes specified in
* the global configuration object, i.e. in the :
* <pre>
* <modules>
* <module id="foo" class="bar" foo1="bar1" ... />
* </modules>
* </pre>
* section of the configuration file.
*
* @param pool the BrokerPool representing the current database instance
* @param config the configuration object
* @throws DatabaseConfigurationException
*/
public IndexManager(BrokerPool pool, Configuration config) throws DatabaseConfigurationException {
this.pool = pool;
Configuration.IndexModuleConfig modConf[] = (Configuration.IndexModuleConfig[])
config.getProperty(PROPERTY_INDEXER_MODULES);
String dataDir = (String) config.getProperty(BrokerPool.PROPERTY_DATA_DIR);
if (modConf != null) {
for (int i = 0; i < modConf.length; i++) {
String className = modConf[i].getClassName();
try {
Class clazz = Class.forName(className);
if (!AbstractIndex.class.isAssignableFrom(clazz)) {
throw new DatabaseConfigurationException("Class " + className + " does not implement " +
AbstractIndex.class.getName());
}
AbstractIndex index = (AbstractIndex)clazz.newInstance();
index.configure(pool, dataDir, modConf[i].getConfig());
index.open();
indexers.put(modConf[i].getId(), index);
if (LOG.isInfoEnabled())
LOG.info("Registered index " + className + " as " + modConf[i].getId());
} catch (ClassNotFoundException e) {
LOG.warn("Class " + className + " not found. Cannot configure index.");
} catch (IllegalAccessException e) {
LOG.warn("Exception while configuring index " + className + ": " + e.getMessage(), e);
} catch (InstantiationException e) {
LOG.warn("Exception while configuring index " + className + ": " + e.getMessage(), e);
}
}
}
}
/**
* Returns the {@link org.exist.storage.BrokerPool} on with this IndexManager operates.
*
* @return the broker pool
*/
public BrokerPool getBrokerPool() {
return pool;
}
/**
* Returns an iterator over the registered indexes.
*
* @return the iterator
*/
protected Iterator iterator() {
return indexers.values().iterator();
}
/**
* Returns the index registered with the provided ID.
*
* @param indexId the ID
* @return the index
*/
public synchronized Index getIndexById(String indexId) {
for (Iterator i = iterator(); i.hasNext(); ) {
Index indexer = (Index) i.next();
if (indexId.equals(indexer.getIndexId()))
return indexer;
}
return null;
}
/**
* Returns the index registered with the provided human-readable name.
* @param indexName the name
* @return the index
*/
public synchronized Index getIndexByName(String indexName) {
return (Index)indexers.get(indexName);
}
/**
* Returns a set of IndexWorkers, one for each registered index. The
* returned IndexWorkers are used by the DBBroker instances to perform the
* actual indexing work.
*
* @return set of IndexWorkers
*/
protected synchronized IndexWorker[] getWorkers(DBBroker broker) {
final IndexWorker workers[] = new IndexWorker[indexers.size()];
Index index;
int j = 0;
for (Iterator i = indexers.values().iterator(); i.hasNext(); j++) {
index = (Index) i.next();
workers[j] = index.getWorker(broker);
}
return workers;
}
/**
* Shutdowns all registered indexes by calling {@link org.exist.indexing.Index#close()}
* on them.
*
* @throws DBException
*/
public void shutdown() throws DBException {
Index index;
for (Iterator i = iterator(); i.hasNext(); ) {
index = (Index) i.next();
index.close();
}
}
/**
* Call indexes to flush all data to disk.
*
* @throws DBException
*/
public void sync() throws DBException {
Index index;
for (Iterator i = iterator(); i.hasNext(); ) {
index = (Index) i.next();
index.sync();
}
}
/**
* Physically destroy the registered indexes by calling {@link org.exist.indexing.Index#remove()}
* on them.
*
* @throws DBException
*/
public void removeIndexes() throws DBException {
Index index;
for (Iterator i = iterator(); i.hasNext();) {
index = (Index) i.next();
index.remove();
}
}
/** Reopens the registered index in case they have been closed by a previous operation
* such as {@link org.exist.indexing.Index#close()} by calling {@link org.exist.indexing.Index#open()}
* on them.
*
* @throws DatabaseConfigurationException
*/
public void reopenIndexes() throws DatabaseConfigurationException {
Index index;
for (Iterator i = iterator(); i.hasNext();) {
index = (Index) i.next();
index.open();
}
}
public void backupToArchive(RawDataBackup backup) throws IOException {
Index index;
for (Iterator i = iterator(); i.hasNext();) {
index = (Index) i.next();
if (index instanceof RawBackupSupport)
((RawBackupSupport)index).backupToArchive(backup);
}
}
}