/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * 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.exoplatform.services.jcr.impl.core.query.lucene; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.Term; import org.apache.lucene.search.Similarity; import org.apache.lucene.store.Directory; import org.apache.lucene.store.IndexInput; import org.apache.lucene.store.IndexOutput; import org.exoplatform.services.jcr.impl.core.query.IndexerIoModeHandler; import org.exoplatform.services.jcr.impl.core.query.lucene.directory.DirectoryManager; import java.io.IOException; /** * Implements a lucene index which is based on a * {@link org.apache.jackrabbit.core.fs.FileSystem}. */ class PersistentIndex extends AbstractIndex { /** The name of this persistent index */ private final String name; /** * If non <code>null</code>, <code>listener</code> needs to be informed * when a document is deleted. */ private IndexListener listener; /** * Creates a new <code>PersistentIndex</code>. * * @param name the name of this index. * @param analyzer the analyzer for text tokenizing. * @param similarity the similarity implementation. * @param cache the document number cache * @param directoryManager the directory manager. * @throws IOException if an error occurs while opening / creating the * index. */ PersistentIndex(String name, Analyzer analyzer, Similarity similarity, DocNumberCache cache, final DirectoryManager directoryManager, IndexerIoModeHandler modeHandler) throws IOException { super(analyzer, similarity, directoryManager.getDirectory(name), cache, modeHandler); this.name = name; if (isExisting()) { IndexMigration.migrate(PersistentIndex.this, directoryManager); } } /** * {@inheritDoc} */ @Override int removeDocument(Term idTerm) throws IOException { int num = super.removeDocument(idTerm); if (num > 0 && listener != null) { listener.documentDeleted(idTerm); } return num; } /** * Merges the provided indexes into this index. After this completes, the * index is optimized. * <br> * The provided IndexReaders are not closed. * * @param readers the readers of indexes to add. * @throws IOException if an error occurs while adding indexes. */ void addIndexes(IndexReader[] readers) throws IOException { getIndexWriter().addIndexes(readers); getIndexWriter().maybeMerge(); } /** * Copies <code>index</code> into this persistent index. This method should * only be called when <code>this</code> index is empty otherwise the * behaviour is undefined. * * @param index the index to copy from. * @throws IOException if an error occurs while copying. */ void copyIndex(final AbstractIndex index) throws IOException { // commit changes to directory on other index. index.commit(true); // simply copy over the files byte[] buffer = new byte[1024]; Directory dir = index.getDirectory(); Directory dest = getDirectory(); String[] files = dir.listAll(); for (int i = 0; i < files.length; i++) { IndexInput in = dir.openInput(files[i]); try { IndexOutput out = dest.createOutput(files[i]); try { long remaining = in.length(); while (remaining > 0) { int num = (int)Math.min(remaining, buffer.length); in.readBytes(buffer, 0, num); out.writeBytes(buffer, num); remaining -= num; } } finally { out.close(); } } finally { in.close(); } } } /** * Returns a <code>ReadOnlyIndexReader</code> and registeres * <code>listener</code> to send notifications when documents are deleted on * <code>this</code> index. * * @param listener the listener to notify when documents are deleted. * @return a <code>ReadOnlyIndexReader</code>. * @throws IOException if the reader cannot be obtained. */ synchronized ReadOnlyIndexReader getReadOnlyIndexReader(IndexListener listener) throws IOException { // Ensure all in-memory changes are persisted before returning reader to merger releaseWriterAndReaders(); ReadOnlyIndexReader reader = getReadOnlyIndexReader(); this.listener = listener; return reader; } /** * Removes a potentially registered {@link IndexListener}. */ synchronized void resetListener() { this.listener = null; } /** * Returns the number of documents in this persistent index. * * @return the number of documents in this persistent index. * @throws IOException if an error occurs while reading from the index. */ int getNumDocuments() throws IOException { return getIndexReader().numDocs(); } /** * Returns the name of this index. * @return the name of this index. */ String getName() { return name; } }