Package org.openbel.framework.core.indexer

Source Code of org.openbel.framework.core.indexer.JDBMLookup

/**
* Copyright (C) 2012-2013 Selventa, Inc.
*
* This file is part of the OpenBEL Framework.
*
* 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 3 of the License, or
* (at your option) any later version.
*
* The OpenBEL Framework 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 the OpenBEL Framework. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms under LGPL v3:
*
* This license does not authorize you and you are prohibited from using the
* name, trademarks, service marks, logos or similar indicia of Selventa, Inc.,
* or, in the discretion of other licensors or authors of the program, the
* name, trademarks, service marks, logos or similar indicia of such authors or
* licensors, in any marketing or advertising materials relating to your
* distribution of the program or any covered product. This restriction does
* not waive or limit your obligation to keep intact all copyright notices set
* forth in the program as delivered to you.
*
* If you distribute the program in whole or in part, or any modified version
* of the program, and you assume contractual liability to the recipient with
* respect to the program or modified version, then you will indemnify the
* authors and licensors of the program for any liabilities that these
* contractual assumptions directly impose on those licensors and authors.
*/
package org.openbel.framework.core.indexer;

import static jdbm.RecordManagerFactory.createRecordManager;
import static org.openbel.framework.common.BELUtilities.noLength;

import java.io.IOException;
import java.util.Collections;
import java.util.Set;

import org.openbel.framework.common.InvalidArgument;

import jdbm.InverseHashView;
import jdbm.PrimaryTreeMap;
import jdbm.RecordManager;
import jdbm.Serializer;

/**
* This class is a low-level means of performing direct lookups against JDBM
* indices.
* <p>
* Bad use of this class can cause file descriptor leaks (see {@link #open()},
* {@link #close()}, and {@link #finalize()}. A better option may be to use
* service-level constructs.
* </p>
*/
abstract class JDBMLookup<K extends Comparable<K>, V> {
    private final String indexPath;
    private final Serializer<V> valueSerializer;
    PrimaryTreeMap<K, V> tmap;
    InverseHashView<K, V> invTmap;
    private final int hash;

    /**
     * Constructs a JDBM lookup for the associated index path.
     *
     * @param indexPath Index path
     * @throws InvalidArgument Thrown if {@code indexPath} is null or empty
     */
    JDBMLookup(String indexPath) {
        this(indexPath, null);
    }

    /**
     * Constructs a JDBM lookup for the associated index path with the provided
     * value {@link Serializer}.
     * @param indexPath Index path
     * @param valueSerializer {@link Serializer} for values. May be <code>null</code>.
     * @throws InvalidArgument Thrown if {@code indexPath} is null or empty
     */
    JDBMLookup(String indexPath, Serializer<V> valueSerializer) {
        if (noLength(indexPath)) {
            throw new InvalidArgument("indexPath", indexPath);
        }
        this.indexPath = indexPath;
        this.valueSerializer = valueSerializer;
        hash = indexPath.hashCode();
    }

    /**
     * Returns the index path associated with this JDBM lookup.
     *
     * @return String
     */
    public String getIndexPath() {
        return indexPath;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int hashCode() {
        return hash;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null) return false;
        if (!(obj instanceof JDBMLookup)) return false;
        @SuppressWarnings("unchecked")
        JDBMLookup<K, V> other = (JDBMLookup<K, V>) obj;
        // indexPath is non-null by contract
        if (!indexPath.equals(other.indexPath)) return false;
        return true;
    }

    /**
     * Closes the record manager, if it has been left open.
     * <p>
     * <blockquote> ... it is a grave error to depend on a finalizer to close
     * files, because open file descriptors are a limited resource. If many
     * files are left open because the JVM is tardy in executing finalizers, a
     * program may fail because it can no longer open files. </blockquote>
     * </p>
     *
     * @see {@link #close()}
     */
    @Override
    protected void finalize() throws Throwable {
        if (tmap == null) {
            return;
        }
        RecordManager rm = tmap.getRecordManager();
        if (rm == null) {
            return;
        }

        // We don't want any exceptions propagating back up the stack
        // and causing problems finalizing this object.
        try {
            rm.close();
        } catch (IOException ioex) {
            // Assume it has been closed.
        }
    }

    /**
     * Opens the index, for subsequent lookups.
     *
     * @throws IOException Thrown if an I/O related exception occurs while
     * creating or opening the record manager
     */
    public synchronized void open() throws IOException {
        if (tmap != null) {
            return;
        }
        final RecordManager rm = createRecordManager(indexPath);
        if (valueSerializer == null) {
            tmap = rm.treeMap(IndexerConstants.INDEX_TREE_KEY);
        } else {
            tmap = rm.treeMap(IndexerConstants.INDEX_TREE_KEY, valueSerializer);
        }
        if (tmap.isEmpty()) {
            rm.close();
            throw new IOException("tree map is empty");
        }
        invTmap = tmap.inverseHashView(IndexerConstants.INVERSE_KEY);
    }

    /**
     * Returns the number of records.
     *
     * @return int
     */
    public int getRecordCount() {
        return tmap.size();
    }

    /**
     * Closes the index.
     *
     * @throws IOException Thrown when one of the underlying I/O operations fail
     * @throws IllegalStateException Thrown if {@link #open()} has not been
     * invoked
     */
    public synchronized void close() throws IOException {
        if (tmap == null) {
            throw new IllegalStateException("not open");
        }
        final RecordManager rm = tmap.getRecordManager();
        rm.close();
        tmap = null;
    }

    /**
     * Performs a lookup for the given {@code key}.
     *
     * @param key Key
     * @return String; may be null for the given key
     */
    public synchronized V lookup(final String key) {
        if (tmap == null) {
            throw new IllegalStateException("not open");
        }
        return tmap.get(key);
    }

    /**
     * Performs a reverse lookup for the given {@code value}.
     * If multiple keys resolve to the same value, this method
     * will return the first key match as per the JDBM impl.
     *
     * @param value
     * @return
     * @see InverseHashView#findKeyForValue(Object)
     */
    public synchronized K reverseLookup(final V value) {
        if (tmap == null) {
            throw new IllegalStateException("not open");
        }
        return invTmap.findKeyForValue(value);
    }

    /**
     * @return an unmodifiable {@link Set} containing {@link String}s
     *         representing namespace values.
     */
    public synchronized Set<K> getKeySet() {
        if (tmap == null) {
            throw new IllegalStateException("not open");
        }
        return Collections.unmodifiableSet(tmap.keySet());
    }
}
TOP

Related Classes of org.openbel.framework.core.indexer.JDBMLookup

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.