Package org.kiji.schema.layout.impl.hbase

Source Code of org.kiji.schema.layout.impl.hbase.ShortColumnNameTranslator

/**
* (c) Copyright 2014 WibiData, Inc.
*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* 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.kiji.schema.layout.impl.hbase;

import com.google.common.base.Objects;
import org.apache.commons.lang.ArrayUtils;
import org.apache.hadoop.hbase.util.Bytes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.kiji.annotations.ApiAudience;
import org.kiji.schema.KijiColumnName;
import org.kiji.schema.NoSuchColumnException;
import org.kiji.schema.hbase.HBaseColumnName;
import org.kiji.schema.layout.HBaseColumnNameTranslator;
import org.kiji.schema.layout.KijiTableLayout;
import org.kiji.schema.layout.KijiTableLayout.LocalityGroupLayout;
import org.kiji.schema.layout.KijiTableLayout.LocalityGroupLayout.FamilyLayout;
import org.kiji.schema.layout.KijiTableLayout.LocalityGroupLayout.FamilyLayout.ColumnLayout;
import org.kiji.schema.layout.impl.ColumnId;

/**
* Translates between HBase and Kiji column names.
*
* <p>This class defines a mapping between names of HBase families/qualifiers and
* Kiji locality group/family/qualifiers using a custom base-64 encoding based on the ids of each
* individual column.</p>
*/
@ApiAudience.Private
public final class ShortColumnNameTranslator extends HBaseColumnNameTranslator {
  private static final Logger LOG = LoggerFactory.getLogger(ShortColumnNameTranslator.class);

  /** Used to separate the Kiji family from the Kiji qualifier in an HBase qualifier. */
  private static final byte SEPARATOR = ':';

  /** The table to translate names for. */
  private final KijiTableLayout mLayout;

  /**
   * Creates a new {@link ShortColumnNameTranslator} instance.
   *
   * @param tableLayout The layout of the table to translate column names for.
   */
  public ShortColumnNameTranslator(KijiTableLayout tableLayout) {
    mLayout = tableLayout;
  }

  /** {@inheritDoc} */
  @Override
  public KijiColumnName toKijiColumnName(HBaseColumnName hbaseColumnName)
      throws NoSuchColumnException {
    LOG.debug("Translating HBase column name '{}' to Kiji column name...", hbaseColumnName);
    final ColumnId localityGroupID = ColumnId.fromByteArray(hbaseColumnName.getFamily());
    final LocalityGroupLayout localityGroup =
        mLayout.getLocalityGroupMap().get(mLayout.getLocalityGroupIdNameMap().get(localityGroupID));
    if (localityGroup == null) {
      throw new NoSuchColumnException(String.format("No locality group with ID %s in table %s.",
          localityGroupID.getId(), mLayout.getName()));
    }

    // Parse the HBase qualifier as a byte[] in order to save a String instantiation
    final byte[] hbaseQualifier = hbaseColumnName.getQualifier();
    final int index = ArrayUtils.indexOf(hbaseQualifier, SEPARATOR);
    if (index == -1) {
      throw new NoSuchColumnException(String.format(
          "Missing separator in HBase column %s.", hbaseColumnName));
    }
    final ColumnId familyID = ColumnId.fromString(Bytes.toString(hbaseQualifier, 0, index));
    final String rawQualifier =
        Bytes.toString(hbaseQualifier, index + 1, hbaseQualifier.length - index - 1);

    final FamilyLayout family =
        localityGroup.getFamilyMap().get(localityGroup.getFamilyIdNameMap().get(familyID));
    if (family == null) {
      throw new NoSuchColumnException(String.format(
          "No family with ID %s in locality group %s of table %s.",
          familyID.getId(), localityGroup.getName(), mLayout.getName()));
    }

    if (family.isGroupType()) {
      // Group type family.
      final ColumnId qualifierID = ColumnId.fromString(rawQualifier);
      final ColumnLayout qualifier =
          family.getColumnMap().get(family.getColumnIdNameMap().get(qualifierID));
      if (qualifier == null) {
        throw new NoSuchColumnException(String.format(
            "No column with ID %s in family %s of table %s.",
            qualifierID.getId(), family.getName(), mLayout.getName()));
      }
      final KijiColumnName kijiColumnName =
          new KijiColumnName(family.getName(), qualifier.getName());
      LOG.debug("Translated to Kiji group column {}.", kijiColumnName);
      return kijiColumnName;
    } else {
      // Map type family.
      assert family.isMapType();
      final KijiColumnName kijiColumnName = new KijiColumnName(family.getName(), rawQualifier);
      LOG.debug("Translated to Kiji map column '{}'.", kijiColumnName);
      return kijiColumnName;
    }
  }

  /** {@inheritDoc} */
  @Override
  public HBaseColumnName toHBaseColumnName(final KijiColumnName kijiColumnName)
      throws NoSuchColumnException {
    final String familyName = kijiColumnName.getFamily();
    final String qualifierName = kijiColumnName.getQualifier();

    final FamilyLayout family = mLayout.getFamilyMap().get(familyName);
    if (family == null) {
      throw new NoSuchColumnException(kijiColumnName.toString());
    }

    final ColumnId localityGroupID = family.getLocalityGroup().getId();
    final ColumnId familyID = family.getId();

    final byte[] localityGroupBytes = Bytes.toBytes(localityGroupID.toString());
    final byte[] familyBytes = Bytes.toBytes(familyID.toString());

    if (qualifierName == null) {
      // Unqualified column
      return new HBaseColumnName(localityGroupBytes,
          concatWithSeparator(SEPARATOR, familyBytes, new byte[]{}));
    } else if (family.isGroupType()) {
      // Group type family.
      final ColumnId qualifierID = family.getColumnIdNameMap().inverse().get(qualifierName);
      final byte[] qualifierBytes = Bytes.toBytes(qualifierID.toString());

      return new HBaseColumnName(localityGroupBytes,
          concatWithSeparator(SEPARATOR, familyBytes, qualifierBytes));
    } else {
      // Map type family.
      assert family.isMapType();
      final byte[] qualifierBytes = Bytes.toBytes(qualifierName);

      return new HBaseColumnName(
          localityGroupBytes,
          concatWithSeparator(SEPARATOR, familyBytes, qualifierBytes));
    }
  }

  /** {@inheritDoc} */
  @Override
  public byte[] toHBaseFamilyName(LocalityGroupLayout localityGroup) {
    return Bytes.toBytes(localityGroup.getId().toString());
  }

  /** {@inheritDoc} */
  @Override
  public KijiTableLayout getTableLayout() {
    return mLayout;
  }

  /**
   * Append the byte arrays with a single byte separator.
   *
   * @param separator to insert between the two arrays.
   * @param a first byte array.
   * @param b second byte array.
   * @return a concatenated with b with a separator byte in between.
   */
  static byte[] concatWithSeparator(byte separator, byte[] a, byte[] b) {
    final byte[] ret = new byte[a.length + b.length + 1];
    System.arraycopy(
        a, 0,      // src, src position
        ret, 0,    // dst, dst position
        a.length); // length
    ret[a.length] = separator;
    System.arraycopy(
        b, 0,              // src, src position
        ret, a.length + 1, // dst, dst position
        b.length);         // length
    return ret;
  }

  /** {@inheritDoc} */
  @Override
  public String toString() {
    return Objects.toStringHelper(this)
        .add("table", mLayout.getName())
        .add("layout", mLayout)
        .toString();
  }
}
TOP

Related Classes of org.kiji.schema.layout.impl.hbase.ShortColumnNameTranslator

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.