Package com.gentics.cr.lucene.facets.taxonomy.taxonomyaccessor

Source Code of com.gentics.cr.lucene.facets.taxonomy.taxonomyaccessor.DefaultTaxonomyAccessor

package com.gentics.cr.lucene.facets.taxonomy.taxonomyaccessor;

import java.io.IOException;
import java.util.Collection;
import java.util.Vector;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;
import org.apache.lucene.analysis.KeywordAnalyzer;
import org.apache.lucene.facet.taxonomy.InconsistentTaxonomyException;
import org.apache.lucene.facet.taxonomy.TaxonomyReader;
import org.apache.lucene.facet.taxonomy.TaxonomyWriter;
import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyReader;
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.store.Directory;
import org.apache.lucene.util.Version;

import com.gentics.cr.lucene.facets.taxonomy.DefaultDirectoryTaxonomyWriter;
import com.gentics.cr.lucene.facets.taxonomy.TaxonomyMapping;

/**
* provides the default implementation for the {@link TaxonomyAccessor}
*
* $Date$
*
* @version $Revision$
* @author Sebastian Vogel <s.vogel@gentics.com>
*/
public class DefaultTaxonomyAccessor implements TaxonomyAccessor {
  private static final OpenMode DEFAULT_WRITER_OPEN_MODE = OpenMode.CREATE_OR_APPEND;

  // TODO: what about searchers do i need to consider those

  /**
   * Log4j logger for error and debug messages.
   */
  private static final Logger LOGGER = Logger
      .getLogger(DefaultTaxonomyAccessor.class);

  // TODO: needed?
  private static final int POOL_SIZE = 10;

  // TODO: needed?
  // private Analyzer analyzer;

  private TaxonomyReader taxoReader = null;

  private TaxonomyWriter taxoWriter = null;

  protected boolean closed = true;

  private Directory directory;

  protected int readerUseCount = 0;

  // TODO: needed?
  protected final ExecutorService pool;

  protected int numReopening = 0;

  protected boolean isReopening = false;

  protected int writerUseCount = 0;

  protected int numSearchersForRetirment = 0;

  protected OpenMode writerOpenMode = null;

  protected static boolean useFacets = false;

  private Vector<TaxonomyMapping> taxonomyMappings = new Vector<TaxonomyMapping>();

  public DefaultTaxonomyAccessor(final OpenMode openMode, Directory dir) {
    directory = dir;
    pool = Executors.newFixedThreadPool(POOL_SIZE);
    this.writerOpenMode = openMode;
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * com.gentics.cr.lucene.taxonomyaccessor.TaxonomyAccessor#getTaxonomyReader
   * ()
   */
  public synchronized TaxonomyReader getTaxonomyReader() throws IOException {
    checkClosed();

    if (taxoReader != null) {
      LOGGER.debug("returning cached taxonomy reader");
      readerUseCount++;
    } else {
      LOGGER.debug("opening new taxonomy reader and caching it");

      taxoReader = new DirectoryTaxonomyReader(directory);
      readerUseCount = 1;
    }
    notifyAll();
    return taxoReader;
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * com.gentics.cr.lucene.taxonomyaccessor.TaxonomyAccessor#getTaxonomyWriter
   * ()
   */
  public synchronized TaxonomyWriter getTaxonomyWriter() throws IOException {
    OpenMode openMode = writerOpenMode;

    if (openMode == null) {
      openMode = DEFAULT_WRITER_OPEN_MODE;
    }

    checkClosed();

    while (writerUseCount > 0) {
      try {
        wait();
      } catch (InterruptedException e) {
      }
    }

    if (taxoWriter != null) {
      LOGGER.debug("returning cached writer:"
          + Thread.currentThread().getId());

      writerUseCount++;
    } else {
      LOGGER.debug("opening new writer and caching it:"
          + Thread.currentThread().getId());

      taxoWriter = new DefaultDirectoryTaxonomyWriter(directory, openMode);
      writerUseCount = 1;
    }

    notifyAll();
    return taxoWriter;
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * com.gentics.cr.lucene.taxonomyaccessor.TaxonomyAccessor#release(org.apache
   * .lucene.facet.taxonomy.TaxonomyReader)
   */
  public synchronized void release(TaxonomyReader reader) {
    if (reader == null) {
      return;
    }

    if (reader != taxoReader) {
      throw new IllegalArgumentException(
          "reading reader not opened by this index accessor");
    }

    readerUseCount--;
    notifyAll();
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * com.gentics.cr.lucene.taxonomyaccessor.TaxonomyAccessor#release(org.apache
   * .lucene.facet.taxonomy.TaxonomyWriter)
   */
  public synchronized void release(TaxonomyWriter writer) {

    try {
      if (writer != taxoWriter) {
        throw new IllegalArgumentException(
            "writer not opened by this index accessor");
      }
      writerUseCount--;

      if (writerUseCount == 0) {
        LOGGER.debug("closing cached writer:"
            + Thread.currentThread().getId());

        try {
          taxoWriter.close();
        } catch (IOException e) {
          LOGGER.error("error closing cached Writer:"
              + Thread.currentThread().getId(), e);
        } finally {
          taxoWriter = null;
        }
      }

    } finally {
      notifyAll();
    }

    if (writerUseCount == 0) {
      numReopening++;
      pool.execute(new Runnable() {
        public void run() {
          synchronized (DefaultTaxonomyAccessor.this) {
            if (numReopening > 5) {
              // there are too many reopens pending, so just bail
              numReopening--;
              return;
            }
            waitForReadersAndRefreshCached();
            numReopening--;
            DefaultTaxonomyAccessor.this.notifyAll();
          }
        }
      });

    }

  }

  /** This method assumes it is invoked in a synchronized context. */
  private void waitForReadersAndRefreshCached() {
    while (readerUseCount > 0) {
      try {
        wait();
      } catch (InterruptedException e) {
      }
    }
    if (numReopening > 1) {
      // there are other calls to reopen pending, so we can bail
      return;
    }
    refreshTaxonomyReader();
  }

  /**
   * Reopens the cached reading Reader. This method assumes it is invoked in a
   * synchronized context.
   */
  private void refreshTaxonomyReader() {
    if (taxoReader == null) {
      return;
    }

    LOGGER.debug("refreshing taxonomy reader");
    try {
      taxoReader.refresh();
    } catch (IOException e) {
      LOGGER.error("error refreshing taxonomy Reader", e);
    } catch (InconsistentTaxonomyException e) {
      LOGGER.info("inconsistent taxononmy found when trying to refresh it", e);
      closeTaxonomyReader();
    } catch(Exception e) {
      LOGGER.info("Could not refresh TaxonomyReader - closing it", e);
      closeTaxonomyReader();
    }

  }

  /*
   * (non-Javadoc)
   *
   * @see com.gentics.cr.lucene.taxonomyaccessor.TaxonomyAccessor#close()
   */
  public synchronized void close() {

    if (closed) {
      return;
    }
    closed = true;
    while ((readerUseCount > 0) || (writerUseCount > 0)
        || (numReopening > 0)) {
      try {
        wait();
      } catch (InterruptedException e) {
      }
    }

    closeTaxonomyReader();
    closeTaxonomyWriter();
    shutdownAndAwaitTermination(pool);
  }

  /**
   * Closes the cached reading Reader if it has been created. This method
   * assumes it is invoked in a synchronized context.
   */
  protected void closeTaxonomyReader() {
    if (taxoReader == null) {
      return;
    }
    LOGGER.debug("closing cached taxonomy reader");

    try {
      taxoReader.close();
    } catch (IOException e) {
      LOGGER.error("error closing taxonomy Reader", e);
    } finally {
      taxoReader = null;
    }
  }

  /**
   * Closes the cached Writer if it has been created. This method is invoked
   * in a synchronized context.
   */
  protected void closeTaxonomyWriter() {
    if (taxoWriter == null) {
      return;
    }
    LOGGER.debug("closing cached taxonomy writer");

    try {
      taxoWriter.close();
    } catch (IOException e) {
      LOGGER.error("error closing cached taxonomy Writer", e);
    } finally {
      taxoWriter = null;
    }
  }

  protected void shutdownAndAwaitTermination(ExecutorService pool) {
    pool.shutdown(); // Disable new tasks from being submitted
    try {
      // Wait a while for existing tasks to terminate
      if (!pool.awaitTermination(20, TimeUnit.SECONDS)) {
        pool.shutdownNow(); // Cancel currently executing tasks
        // Wait a while for tasks to respond to being cancelled
        if (!pool.awaitTermination(60, TimeUnit.SECONDS))
          System.err.println("Pool did not terminate");
      }
    } catch (InterruptedException ie) {
      // (Re-)Cancel if current thread also interrupted
      pool.shutdownNow();
      // Preserve interrupt status
      Thread.currentThread().interrupt();
    }
  }

  /**
   * Throws an Exception if TaxonomyAccessor is closed. This method assumes it
   * is invoked in a synchronized context.
   */
  private void checkClosed() {
    if (closed) {
      throw new IllegalStateException("taxonomy accessor has been closed");
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * com.gentics.cr.lucene.taxonomyaccessor.TaxonomyAccessor#writerUseCount()
   */
  public int writerUseCount() {
    return writerUseCount;
  }

  /*
   * (non-Javadoc)
   *
   * @see com.gentics.cr.lucene.taxonomyaccessor.TaxonomyAccessor#isOpen()
   */
  public boolean isOpen() {
    return !closed;
  }

  /*
   * (non-Javadoc)
   *
   * @see com.gentics.cr.lucene.taxonomyaccessor.TaxonomyAccessor#isLocked()
   */
  public boolean isLocked() {
    boolean locked = false;
    try {
      locked = IndexWriter.isLocked(directory);
    } catch (IOException e) {
      LOGGER.error(e);
    }
    return locked;
  }

  /*
   * (non-Javadoc)
   *
   * @see com.gentics.cr.lucene.taxonomyaccessor.TaxonomyAccessor#open()
   */
  public synchronized void open() {
    closed = false;
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * com.gentics.cr.lucene.taxonomyaccessor.TaxonomyAccessor#addTaxonomyMapping
   * (com.gentics.cr.lucene.taxonomyaccessor.TaxonomyMapping)
   */
  public void addTaxonomyMapping(TaxonomyMapping mapping) {
    taxonomyMappings.add(mapping);
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * com.gentics.cr.lucene.taxonomyaccessor.TaxonomyAccessor#getTaxonomyMappings
   * ()
   */
  public Collection<TaxonomyMapping> getTaxonomyMappings() {
    return taxonomyMappings;
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * com.gentics.cr.lucene.taxonomyaccessor.TaxonomyAccessor#addTaxonomyMappings
   * (java.util.Collection)
   */
  public void addTaxonomyMappings(
      Collection<? extends TaxonomyMapping> mappings) {
    taxonomyMappings.addAll(mappings);
  }

  /**
   * {@inheritDoc}
   */
  public synchronized void refresh() {
    waitForReadersAndRefreshCached();
  }

  /**
   * {@inheritDoc}
   */
  public synchronized void clearTaxonomy() {
    checkClosed();

    while (writerUseCount > 0) {
      try {
        wait();
      } catch (InterruptedException e) {
      }
    }
    closeTaxonomyWriter();
   
    // Workaround for missing delete all method in the TaxonomyWriter
    IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_30,
              new KeywordAnalyzer()).setOpenMode(this.writerOpenMode).setMergePolicy(
              new LogByteSizeMergePolicy());    
    try {     
      IndexWriter indexWriter = new IndexWriter(directory, config);
      indexWriter.deleteAll();
      indexWriter.close();
      // the TaxonomyReader should be refreshed after this but only if the IndexReaders have been reopened before
    } catch (IOException e) {
      LOGGER.error("Could not clear the Taxonomy", e);
    }
    notifyAll();

  }
}
TOP

Related Classes of com.gentics.cr.lucene.facets.taxonomy.taxonomyaccessor.DefaultTaxonomyAccessor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.