dk.defxws.fgslucene.IndexWriterCache.java Source code

Java tutorial

Introduction

Here is the source code for dk.defxws.fgslucene.IndexWriterCache.java

Source

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at license/ESCIDOC.LICENSE
 * or http://www.escidoc.de/license.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at license/ESCIDOC.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2006-2008 Fachinformationszentrum Karlsruhe Gesellschaft
 * fuer wissenschaftlich-technische Information mbH and Max-Planck-
 * Gesellschaft zur Foerderung der Wissenschaft e.V.  
 * All rights reserved.  Use is subject to license terms.
 */
package dk.defxws.fgslucene;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.index.LogByteSizeMergePolicy;
import org.apache.lucene.index.Term;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.MMapDirectory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.escidoc.sb.common.Constants;
import dk.defxws.fedoragsearch.server.Config;
import dk.defxws.fedoragsearch.server.errors.GenericSearchException;

/**
 * @author mih
 * 
 *         Singleton for caching IndexWriters (one for each index)
 * 
 */
public final class IndexWriterCache {

    private static IndexWriterCache instance = null;

    private static final Logger logger = LoggerFactory.getLogger(IndexWriterCache.class);

    /** Holds IndexWriter for each index. */
    private Map<String, IndexWriter> indexWriters = new HashMap<String, IndexWriter>();

    private Object lockObject = new Object();

    /**
     * private Constructor for Singleton.
     * 
     */
    private IndexWriterCache() {
    }

    /**
     * Only initialize Object once. Check for old objects in cache.
     * 
     * @return IndexWriterCache IndexWriterCache
     * 
     */
    public static synchronized IndexWriterCache getInstance() {
        if (instance == null) {
            instance = new IndexWriterCache();
        }
        return instance;
    }

    /**
     * delete document with given PID in index with given indexName.
     * 
     * @param indexName
     *            name of index to open.
     * @param config
     *            gsearch config-Object.
     * @param pid
     *            PID to update.
     * @param commit
     *            wether to commit indexWriter or not.
     * @throws GenericSearchException
     *             e
     */
    public void delete(final String indexName, final Config config, final String pid, final boolean commit)
            throws GenericSearchException {
        synchronized (lockObject) {
            try {
                getIndexWriter(indexName, false, config).deleteDocuments(new Term("PID", pid));
                commitIndexWriter(indexName, config);
            } catch (Throwable e) {
                closeIndexWriter(indexName);
                throw new GenericSearchException(
                        "updateIndex deletePid error indexName=" + indexName + " pid=" + pid + "\n", e);
            }
        }
    }

    /**
     * update document with given PID in index with given indexName.
     * 
     * @param indexName
     *            name of index to open.
     * @param config
     *            gsearch config-Object.
     * @param pid
     *            PID to update.
     * @param doc
     *            Update-Document.
     * @param commit
     *            wether to commit indexWriter or not.
     * @throws GenericSearchException
     *             e
     */
    public void update(final String indexName, final Config config, final String pid, final Document doc,
            final boolean commit) throws GenericSearchException {
        synchronized (lockObject) {
            try {
                getIndexWriter(indexName, false, config).updateDocument(new Term("PID", pid), doc);
                commitIndexWriter(indexName, config);

            } catch (Throwable e) {
                closeIndexWriter(indexName);
                throw new GenericSearchException("updateIndex error indexName=" + indexName + " pid=" + pid + "\n",
                        e);
            }
        }
    }

    /**
     * optimize index for given indexName.
     * 
     * @param indexName
     *            name of index to open.
     * @param config
     *            gsearch config-Object.
     * @throws GenericSearchException
     *             e
     */
    public void optimize(final String indexName, final Config config) throws GenericSearchException {
        synchronized (lockObject) {
            try {
                getIndexWriter(indexName, false, config).optimize();
                commitIndexWriter(indexName, config);
            } catch (Throwable e) {
                closeIndexWriter(indexName);
                throw new GenericSearchException("updateIndex optimize error indexName=" + indexName, e);
            }
        }
    }

    /**
     * commit IndexWriter to persist to File.
     * 
     * @param indexName
     *            name of index to open.
     * @param config
     *            gsearch config-Object.
     * @throws GenericSearchException
     *             e
     */
    public void commit(final String indexName, final Config config) throws GenericSearchException {
        synchronized (lockObject) {
            try {
                closeIndexWriter(indexName);
            } catch (IOException e) {
                throw new GenericSearchException("commit error indexName=" + indexName + "\n", e);
            }
        }
    }

    /**
     * create empty index for given indexName.
     * 
     * @param indexName
     *            name of index to open.
     * @param config
     *            gsearch config-Object.
     * @throws GenericSearchException
     *             e
     */
    public void createEmpty(final String indexName, final Config config) throws GenericSearchException {
        synchronized (lockObject) {
            closeIndexWriter(indexName);
            getIndexWriter(indexName, true, config);
            closeIndexWriter(indexName);
        }
    }

    /**
     * get IndexWriter for given indexPath and write it into cache.
     * 
     * @param indexName
     *            name of index to open.
     * @param config
     *            gsearch config-Object.
     * @throws GenericSearchException
     *             e
     */
    private IndexWriter getIndexWriter(final String indexName, final boolean create, final Config config)
            throws GenericSearchException {
        if (indexWriters.get(indexName) == null) {
            IndexWriter iw = null;
            try {
                IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Constants.LUCENE_VERSION,
                        getAnalyzer(config.getAnalyzer(indexName)));
                if (create) {
                    indexWriterConfig.setOpenMode(OpenMode.CREATE);
                } else {
                    indexWriterConfig.setOpenMode(OpenMode.CREATE_OR_APPEND);
                }
                if (config.getMaxBufferedDocs(indexName) > 1) {
                    indexWriterConfig.setMaxBufferedDocs(config.getMaxBufferedDocs(indexName));
                }
                if (config.getRamBufferSizeMb(indexName) > 1) {
                    indexWriterConfig.setRAMBufferSizeMB(config.getRamBufferSizeMb(indexName));
                }

                if (config.getMergeFactor(indexName) > 1 || config.getMaxMergeDocs(indexName) > 1
                        || config.getMaxMergeMb(indexName) > 1) {
                    LogByteSizeMergePolicy logMergePolicy = new LogByteSizeMergePolicy();
                    if (config.getMergeFactor(indexName) > 1) {
                        logMergePolicy.setMergeFactor(config.getMergeFactor(indexName));
                    }
                    if (config.getMaxMergeDocs(indexName) > 1) {
                        logMergePolicy.setMaxMergeDocs(config.getMaxMergeDocs(indexName));
                    }
                    if (config.getMaxMergeMb(indexName) > 1) {
                        logMergePolicy.setMaxMergeMB(config.getMaxMergeMb(indexName));
                    }
                    indexWriterConfig.setMergePolicy(logMergePolicy);
                }
                if (config.getDefaultWriteLockTimeout(indexName) > 1) {
                    indexWriterConfig.setWriteLockTimeout(config.getDefaultWriteLockTimeout(indexName));
                }
                if (config.getLuceneDirectoryImplementation(indexName) != null) {
                    // Initialize IndexWriter with configured FSDirectory
                    FSDirectory directory = getDirectoryImplementation(
                            config.getLuceneDirectoryImplementation(indexName),
                            new File(config.getIndexDir(indexName)));
                    iw = new IndexWriter(directory, indexWriterConfig);
                } else {
                    // Initialize IndexWriter with default FSDirectory
                    iw = new IndexWriter(FSDirectory.open(new File(config.getIndexDir(indexName))),
                            indexWriterConfig);
                }
                if (config.getMaxChunkSize(indexName) > 1) {
                    if (iw.getDirectory() instanceof MMapDirectory) {
                        ((MMapDirectory) iw.getDirectory()).setMaxChunkSize(config.getMaxChunkSize(indexName));
                    }
                }
            } catch (Exception e) {
                iw = null;
                throw new GenericSearchException(
                        "IndexWriter new error, creating index indexName=" + indexName + " :\n", e);
            }
            indexWriters.put(indexName, iw);
            if (logger.isDebugEnabled())
                logger.debug("getIndexWriter put to map " + iw);
            return iw;
        }
        return indexWriters.get(indexName);
    }

    /**
     * close IndexWriter for given indexPath.
     * 
     * @param indexName
     *            name of index to open.
     * @throws GenericSearchException
     *             e
     */
    private void closeIndexWriter(final String indexName) throws GenericSearchException {
        IndexWriter iw = null;
        try {
            if ((iw = indexWriters.get(indexName)) != null) {
                if (logger.isDebugEnabled())
                    logger.debug("closeIndexWriter got from map - try to close " + iw);
                indexWriters.get(indexName).close();
                indexWriters.put(indexName, null);
            }
        } catch (IOException e) {
            iw = indexWriters.get(indexName);
            iw = null;
            indexWriters.put(indexName, null);
            throw new GenericSearchException(e.getMessage());
        }
    }

    /**
     * commits changes in IndexWriter for given indexPath.
     * 
     * @param iw
     *            IndexWriter to commit.
     * @throws GenericSearchException
     *             e
     */
    private void commitIndexWriter(final String indexName, final Config config) throws GenericSearchException {
        try {
            getIndexWriter(indexName, false, config).commit();
        } catch (Throwable e) {
            closeIndexWriter(indexName);
            throw new GenericSearchException("commitIndexWriter error indexName=" + indexName, e);

        }
    }

    /**
     * get Analyzer Object from ClassName.
     * 
     * @param analyzerClassName
     *            name of Analyzer-class.
     * @throws GenericSearchException
     *             e
     */
    private Analyzer getAnalyzer(String analyzerClassName) throws GenericSearchException {
        Analyzer analyzer = null;
        if (logger.isDebugEnabled())
            logger.debug("analyzerClassName=" + analyzerClassName);
        try {
            Class analyzerClass = Class.forName(analyzerClassName);
            if (logger.isDebugEnabled())
                logger.debug("analyzerClass=" + analyzerClass.toString());
            analyzer = (Analyzer) analyzerClass.getConstructor(new Class[] {}).newInstance(new Object[] {});
            if (logger.isDebugEnabled())
                logger.debug("analyzer=" + analyzer.toString());
        } catch (ClassNotFoundException e) {
            throw new GenericSearchException(analyzerClassName + ": class not found.\n", e);
        } catch (Exception e) {
            throw new GenericSearchException(analyzerClassName + ": instantiation error.\n", e);
        }
        return analyzer;
    }

    public FSDirectory getDirectoryImplementation(String dirImplClassName, File file)
            throws GenericSearchException {
        FSDirectory directory = null;
        if (logger.isDebugEnabled())
            logger.debug("directoryImplementationClassName=" + dirImplClassName);
        try {
            Class dirImplClass = Class.forName(dirImplClassName);
            if (logger.isDebugEnabled())
                logger.debug("directoryImplementationClass=" + dirImplClass.toString());
            directory = (FSDirectory) dirImplClass.getConstructor(new Class[] { File.class })
                    .newInstance(new Object[] { file });
            if (logger.isDebugEnabled())
                logger.debug("directory=" + directory.toString());
        } catch (ClassNotFoundException e) {
            throw new GenericSearchException(dirImplClassName + ": class not found.\n", e);
        } catch (InstantiationException e) {
            throw new GenericSearchException(dirImplClassName + ": instantiation error.\n", e);
        } catch (IllegalAccessException e) {
            throw new GenericSearchException(dirImplClassName + ": instantiation error.\n", e);
        } catch (InvocationTargetException e) {
            throw new GenericSearchException(dirImplClassName + ": instantiation error.\n", e);
        } catch (NoSuchMethodException e) {
            throw new GenericSearchException(dirImplClassName + ": instantiation error.\n", e);
        }
        return directory;
    }

}