org.cloudgraph.hbase.io.DistributedGraphReader.java Source code

Java tutorial

Introduction

Here is the source code for org.cloudgraph.hbase.io.DistributedGraphReader.java

Source

/**
 * Copyright 2017 TerraMeta Software, Inc.
 * 
 * Licensed 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.cloudgraph.hbase.io;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.namespace.QName;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.cloudgraph.hbase.connect.Connection;
import org.cloudgraph.state.GraphRow;
import org.cloudgraph.store.mapping.StoreMapping;
import org.cloudgraph.store.mapping.TableMapping;
import org.plasma.sdo.PlasmaType;

import commonj.sdo.DataObject;
import commonj.sdo.Type;

/**
 * Encapsulates one or more graph table reader components for federation across
 * multiple physical tables and/or physical table rows. Maps physical configured
 * table names to respective table readers. In most usage scenarios, a "root"
 * table reader is typically added initially, then other reader are
 * incrementally added as association target types are detected and found
 * configured as graph roots within another distinct table context.
 * <p>
 * Acts as a container for one or more {@link TableReader} elements
 * encapsulating a set of component table read operations for distributed
 * assembly across multiple tables, or a single table in the most simple
 * (degenerate) case.
 * </p>
 * 
 * @see org.cloudgraph.hbase.io.GraphTableReader
 * @see org.cloudgraph.state.GraphTable
 * @author Scott Cinnamond
 * @since 0.5.1
 */
public class DistributedGraphReader implements DistributedReader {

    private static Log log = LogFactory.getLog(DistributedGraphReader.class);

    private TableReader rootReader;
    /** maps table names to table readers */
    private Map<String, TableReader> tableReaderMap = new HashMap<String, TableReader>();
    /** maps qualified graph-root type names to table readers */
    private Map<QName, TableReader> typeTableReaderMap = new HashMap<QName, TableReader>();
    /** maps table readers to graph-root types */
    private Map<TableReader, List<Type>> tableReaderTypeMap = new HashMap<TableReader, List<Type>>();

    // maps data objects to row readers
    private Map<Integer, RowReader> rowReaderMap = new HashMap<Integer, RowReader>();

    private Connection connection;

    @SuppressWarnings("unused")
    private DistributedGraphReader() {
    }

    public DistributedGraphReader(Type rootType, List<Type> types, Connection connection) {
        PlasmaType root = (PlasmaType) rootType;

        TableMapping rootTable = StoreMapping.getInstance().getTable(root.getQualifiedName());
        this.connection = connection;

        TableReader tableReader = new GraphTableReader(rootTable, this);
        this.tableReaderMap.put(tableReader.getTableConfig().getName(), tableReader);

        this.rootReader = tableReader;
        this.typeTableReaderMap.put(((PlasmaType) rootType).getQualifiedName(), this.rootReader);
        List<Type> list = new ArrayList<Type>();
        this.tableReaderTypeMap.put(this.rootReader, list);
        list.add(rootType);

        for (Type t : types) {
            PlasmaType type = (PlasmaType) t;
            TableMapping table = StoreMapping.getInstance().findTable(type.getQualifiedName());
            if (table == null)
                continue; // not a graph root

            tableReader = this.tableReaderMap.get(table.getName());
            if (tableReader == null) {
                // create a new table reader if not added already, e.g.
                // as root above or from a graph root type
                // mapped to a table we have seen here
                tableReader = new GraphTableReader(table, this);
                this.tableReaderMap.put(tableReader.getTableConfig().getName(), tableReader);
            }

            // always map root types
            this.typeTableReaderMap.put(type.getQualifiedName(), tableReader);

            list = this.tableReaderTypeMap.get((TableOperation) tableReader);
            if (list == null) {
                list = new ArrayList<Type>();
                this.tableReaderTypeMap.put(tableReader, list);
            }
            if (!list.contains(type))
                list.add(type);
        }
    }

    /**
     * Returns the table reader for the given configured table name, or null of
     * not exists.
     * 
     * @param tableName
     *          the name of the configured table.
     * @return the table reader for the given configured table name, or null of
     *         not exists.
     */
    @Override
    public TableReader getTableReader(String tableName) {
        return this.tableReaderMap.get(tableName);
    }

    /**
     * Returns the table reader for the given qualified type name, or null if not
     * exists.
     * 
     * @param qualifiedTypeName
     *          the qualified type name.
     * @return the table reader for the given qualified type name, or null if not
     *         exists.
     */
    public TableReader getTableReader(QName qualifiedTypeName) {
        return this.typeTableReaderMap.get(qualifiedTypeName);
    }

    /**
     * Adds the given table reader to the container
     * 
     * @param reader
     *          the table reader.
     */
    @Override
    public void addTableReader(TableReader reader) {
        String name = reader.getTableConfig().getName();
        if (this.tableReaderMap.get(name) != null)
            throw new OperationException("table reader for '" + name + "' already exists");
        this.tableReaderMap.put(name, reader);
    }

    /**
     * Returns the count of table readers for this container.
     * 
     * @return the count of table readers for this container
     */
    @Override
    public int getTableReaderCount() {
        return this.tableReaderMap.size();
    }

    /**
     * Returns all table readers for the this container
     * 
     * @return all table readers for the this container
     */
    public List<TableReader> getTableReaders() {
        List<TableReader> result = new ArrayList<TableReader>();
        result.addAll(this.tableReaderMap.values());
        return result;
    }

    /**
     * Returns the table reader associated with the data graph root.
     * 
     * @return the table reader associated with the data graph root.
     */
    public TableReader getRootTableReader() {
        return this.rootReader;
    }

    /**
     * Sets the table reader associated with the data graph root.
     * 
     * @param reader
     *          the table reader
     */
    public void setRootTableReader(TableReader reader) {
        this.rootReader = reader;
        this.tableReaderMap.put(rootReader.getTableConfig().getName(), rootReader);
    }

    /**
     * Returns the row reader associated with the given data object
     * 
     * @param dataObject
     *          the data object
     * @return the row reader associated with the given data object
     * @throws IllegalArgumentException
     *           if the given data object is not associated with any row reader.
     */
    public RowReader getRowReader(DataObject dataObject) {
        RowReader result = rowReaderMap.get(dataObject.hashCode());
        if (result == null)
            throw new IllegalArgumentException("the given data object of type " + dataObject.getType()
                    + " is not associated with any row reader");
        return result;
    }

    public void mapRowReader(DataObject dataObject, RowReader rowReader) {
        int key = dataObject.hashCode();
        RowReader existing = this.rowReaderMap.get(key);
        if (existing != null) {
            if (log.isDebugEnabled())
                log.debug("the given data object of type " + dataObject.getType()
                        + " is already associated with a row reader - ignoring");
            return;
        }

        rowReaderMap.put(key, rowReader);
    }

    @Override
    public void mapRowReader(long dataObjectSequence, PlasmaType type, RowReader rowReader) {

        int key = GraphRow.getHashCode(dataObjectSequence, type);
        RowReader existing = this.rowReaderMap.get(key);
        if (existing != null) {
            if (log.isDebugEnabled())
                log.debug("the given data object with sequence " + dataObjectSequence + " of type " + type
                        + " is already associated with a row reader - ignoring");
            return;
        }

        rowReaderMap.put(key, rowReader);
    }

    @Override
    public void mapRowReader(byte[] rowKey, RowReader rowReader) {
        int key = Arrays.hashCode(rowKey);
        RowReader existing = this.rowReaderMap.get(key);
        if (existing != null) {
            if (log.isDebugEnabled())
                log.debug("the given row key " + rowKey + " is already associated with a row reader - ignoring");
            return;
        }

        rowReaderMap.put(key, rowReader);
    }

    /**
     * Returns a list of types associated with the given table reader.
     * 
     * @param reader
     *          the table reader
     * @return a list of types associated with the given table reader.
     */
    @Override
    public List<Type> getTypes(TableReader operation) {
        return this.tableReaderTypeMap.get(operation);
    }

    /**
     * Returns true if only one table operation exists with only one associated
     * (root) type for this operation.
     * 
     * @return true if only one table operation exists with only one associated
     *         (root) type for this operation.
     */
    public boolean hasSingleRootType() {
        if (this.getTableReaderCount() == 1 && this.getTypes(this.rootReader).size() == 1) {
            return true;
        } else
            return false;
    }

    /**
     * Frees resources associated with this reader and any component readers.
     */
    public void clear() {
        this.rowReaderMap.clear();
        // table readers are created based entirely on metadata
        // i.e. selected types for a query
        for (TableReader tableReader : tableReaderMap.values())
            tableReader.clear();
    }

    @Override
    public Connection getConnection() {
        return this.connection;
    }

    @Override
    public void close() {
        for (TableReader reader : this.getTableReaders()) {
            reader.close();
        }
        // don't close the connection here, we don't own it
        this.connection = null;
    }

}