Package org.kiji.schema

Source Code of org.kiji.schema.KijiURI

/**
* (c) Copyright 2012 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;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collection;
import java.util.regex.Pattern;

import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSortedSet;

import org.kiji.annotations.ApiAudience;
import org.kiji.annotations.ApiStability;
import org.kiji.schema.hbase.HBaseKijiURI.HBaseKijiURIBuilder;
import org.kiji.schema.impl.KijiURIParser;
import org.kiji.schema.impl.KijiURIParser.ZooKeeperAuthorityParser;
import org.kiji.schema.util.KijiNameValidator;
import org.kiji.schema.zookeeper.ZooKeeperFactory;

/**
* a {@code URI} that uniquely identifies a Kiji instance, table, and column-set.
* Use {@value org.kiji.schema.KConstants#DEFAULT_HBASE_URI} for the default Kiji instance URI.
*
* <p>
*
* {@code KijiURI} objects can be constructed directly from parsing a URI string:
* <pre><code>
* final KijiURI uri = KijiURI.newBuilder("kiji://.env/default/mytable/col").build();
* </code></pre>
*
* <p>
*
* Alternatively, {@code KijiURI} objects can be constructed from components by using a builder:
* <pre><code>
* final KijiURI uri = KijiURI.newBuilder()
*   .withInstanceName("default")
*   .withTableName("mytable")
*   .addColumnName(KijiColumnName.create(col))
*   .build();
* </code></pre>
*
* <H2>Syntax</H2>
*
* A KijiURI is composed of multiple components: a {@code scheme}, a {@code cluster-identifier},
* and optionally, an {@code instance-name}, a {@code table-name}, and {@code column-names}.
* The text format of a {@code KijiURI} must be of the form:
* <pre><code>
* scheme://cluster-identifier[/instance-name[/table-name[/column-names]]]
* </code></pre>
* where square brackets indicate optional components.
*
* <H3>Scheme</H3>
*
* The scheme of all {@code KijiURI}s is a identifier prefixed with the string "{@code kiji}", and
* followed by any combination of letters, digits, plus ("+"), period ("."), or hyphen ("-").
* <p>
* The scheme is specific to the type of cluster identified, and determines how the remaining
* components will be parsed.
* <p>
* The default {@code KijiURI} scheme is "{@value #KIJI_SCHEME}". When this scheme is parsed an
* {@link org.kiji.schema.hbase.HBaseKijiURI} will be created.
*
* <H3>Cluster Identifier</H3>
*
* The cluster identifier contains the information necessary for Kiji to identify the host cluster.
* The exact form of the cluster identifier is specific to the cluster type (which is identified
* by the scheme).
*
* At a minimum, the cluster identifier includes ZooKeeper ensemble information for connecting to
* the ZooKeeper service hosting Kiji. The ZooKeeper Ensemble address is located in the 'authority'
* position as defined in RFC3986, and may take one of the following host/port forms, depending on
* whether one or more hosts is specified, and whether a port is specified:
*
* <li> {@code .env}
* <li> {@code host}
* <li> {@code host:port}
* <li> {@code host1,host2}
* <li> {@code (host1,host2):port}
*
* The {@value #ENV_URI_STRING} value will resolve at runtime to a ZooKeeper ensemble address
* taken from the environment. Specifics of how the address is resolved is scheme-specific.
* <p>
* Note that, depending on the scheme, the cluster identifier may contain path segments, and thus
* is potentially larger than just the URI authority.
*
* <H3>Instance Name</H3>
*
* The instance name component is optional. Identifies a Kiji instance hosted on the cluster.
* Only valid Kiji instance names may be used.
*
* <H3>Table Name</H3>
*
* The table name component is optional, and may only be used if the instance name is defined.
* The table name identifies a Kiji table in the identified instance. Only a valid Kiji table name
* may be used.
*
* <H3>Column Names</H3>
*
* The column names component is optional, and may only be used if the table name is defined.
* The column names identify a set of Kiji column names in the specified table. The column names
* are comma separated with no spaces, and may contain only valid Kiji column names.
*
* <H2>Examples</H2>
*
* The following are valid {@code KijiURI}s:
*
* <li> {@code kiji://zkHost}
* <li> {@code kiji://zkHost/instance}
* <li> {@code kiji://zkHost/instance/table}
* <li> {@code kiji://zkHost:zkPort/instance/table}
* <li> {@code kiji://zkHost1,zkHost2/instance/table}
* <li> {@code kiji://(zkHost1,zkHost2):zkPort/instance/table}
* <li> {@code kiji://zkHost/instance/table/col}
* <li> {@code kiji://zkHost/instance/table/col1,col2}
* <li> {@code kiji://.env/instance/table}
*
* <H2>Usage</H2>
*
* The {@link KijiURI} class is not directly instantiable (it is effectively {@code abstract}).
* The builder will instead return a concrete subclass based on the scheme of the provided URI or
* URI string. If no URI or URI string is provided to create the builder, then the default
* {@link org.kiji.schema.hbase.HBaseKijiURI} will be assumed.
*
* All {@link KijiURI} implementations are immutable and thread-safe.
*/
@ApiAudience.Public
@ApiStability.Stable
public class KijiURI {

  /**
   * Default {@code KijiURI} scheme. When a {@code KijiURI} with this scheme is parsed, the default
   * {@code KijiURI} type ({@link org.kiji.schema.hbase.HBaseKijiURI}) is used.
   */
  public static final String KIJI_SCHEME = "kiji";

  /** String to specify an unset KijiURI field. */
  public static final String UNSET_URI_STRING = ".unset";

  /** String to specify a value through the local environment. */
  public static final String ENV_URI_STRING = ".env";

  /** Default Zookeeper port. */
  public static final int DEFAULT_ZOOKEEPER_CLIENT_PORT = 2181;


  /** Pattern matching "(host1,host2,host3):port". */
  public static final Pattern RE_AUTHORITY_GROUP = Pattern.compile("\\(([^)]+)\\):(\\d+)");

  /** Pattern matching valid Kiji schemes. */
  private static final Pattern RE_SCHEME = Pattern.compile("(?i)kiji[a-z+.-0-9]*://.*");

  /**
   * The scheme of this KijiURI.
   */
  private final String mScheme;

  /**
   * Ordered list of Zookeeper quorum host names or IP addresses.
   * Preserves user ordering. Never null.
   */
  private final ImmutableList<String> mZookeeperQuorum;

  /** Normalized (sorted) version of mZookeeperQuorum. Never null. */
  private final ImmutableList<String> mZookeeperQuorumNormalized;

  /** Zookeeper client port number. */
  private final int mZookeeperClientPort;

  /** Kiji instance name. Null means unset. */
  private final String mInstanceName;

  /** Kiji table name. Null means unset. */
  private final String mTableName;

  /** Kiji column names. Never null. Empty means unset. Preserves user ordering. */
  private final ImmutableList<KijiColumnName> mColumnNames;

  /** Normalized version of mColumnNames. Never null. */
  private final ImmutableList<KijiColumnName> mColumnNamesNormalized;

  /**
   * Constructs a new KijiURI with the given parameters.
   *
   * @param scheme of the KijiURI.
   * @param zookeeperQuorum Zookeeper quorum.
   * @param zookeeperClientPort Zookeeper client port.
   * @param instanceName Instance name.
   * @param tableName Table name.
   * @param columnNames Column names.
   * @throws KijiURIException If the parameters are invalid.
   */
  protected KijiURI(
      final String scheme,
      final Iterable<String> zookeeperQuorum,
      final int zookeeperClientPort,
      final String instanceName,
      final String tableName,
      final Iterable<KijiColumnName> columnNames
  ) {
    mScheme = scheme;
    mZookeeperQuorum = ImmutableList.copyOf(zookeeperQuorum);
    mZookeeperQuorumNormalized = ImmutableSortedSet.copyOf(mZookeeperQuorum).asList();
    mZookeeperClientPort = zookeeperClientPort;
    mInstanceName =
        ((null == instanceName) || !instanceName.equals(UNSET_URI_STRING)) ? instanceName : null;
    mTableName = ((null == tableName) || !tableName.equals(UNSET_URI_STRING)) ? tableName : null;
    mColumnNames = ImmutableList.copyOf(columnNames);
    mColumnNamesNormalized = ImmutableSortedSet.copyOf(mColumnNames).asList();
    validateNames();
  }

  /**
   * Builder class for constructing KijiURIs.
   */
  public static class KijiURIBuilder {

    /**
     * The scheme of the KijiURI being built.
     */
    protected String mScheme;

    /**
     * Zookeeper quorum: comma-separated list of Zookeeper host names or IP addresses.
     * Preserves user ordering.
     */
    protected ImmutableList<String> mZookeeperQuorum;

    /** Zookeeper client port number. */
    protected int mZookeeperClientPort;

    /** Kiji instance name. Null means unset. */
    protected String mInstanceName;

    /** Kiji table name. Null means unset. */
    protected String mTableName;

    /** Kiji column names. Never null. Empty means unset. Preserves user ordering. */
    protected ImmutableList<KijiColumnName> mColumnNames;

    /**
     * Constructs a new builder for KijiURIs.
     *
     * @param scheme of the URI.
     * @param zookeeperQuorum The initial zookeeper quorum.
     * @param zookeeperClientPort The initial zookeeper client port.
     * @param instanceName The initial instance name.
     * @param tableName The initial table name.
     * @param columnNames The initial column names.
     */
    protected KijiURIBuilder(
        final String scheme,
        final Iterable<String> zookeeperQuorum,
        final int zookeeperClientPort,
        final String instanceName,
        final String tableName,
        final Iterable<KijiColumnName> columnNames) {
      mScheme = scheme;
      mZookeeperQuorum = ImmutableList.copyOf(zookeeperQuorum);
      mZookeeperClientPort = zookeeperClientPort;
      mInstanceName =
          ((null == instanceName) || !instanceName.equals(UNSET_URI_STRING)) ? instanceName : null;
      mTableName = ((null == tableName) || !tableName.equals(UNSET_URI_STRING)) ? tableName : null;
      mColumnNames = ImmutableList.copyOf(columnNames);
    }

    /**
     * Constructs a new builder for KijiURIs with default values.
     * See {@link KijiURI#newBuilder()} for specific values.
     */
    protected KijiURIBuilder() {
      mScheme = KIJI_SCHEME;
      mZookeeperQuorum = ZooKeeperAuthorityParser.ENV_ZOOKEEPER_QUORUM;
      mZookeeperClientPort = ZooKeeperAuthorityParser.ENV_ZOOKEEPER_CLIENT_PORT;
      mInstanceName = KConstants.DEFAULT_INSTANCE_NAME;
      mTableName = UNSET_URI_STRING;
      mColumnNames = ImmutableList.of();
    }

    /**
     * Configures the KijiURI with Zookeeper Quorum.
     *
     * @param zookeeperQuorum The zookeeper quorum.
     * @return This builder instance so you may chain configuration method calls.
     */
    public KijiURIBuilder withZookeeperQuorum(String[] zookeeperQuorum) {
      mZookeeperQuorum = ImmutableList.copyOf(zookeeperQuorum);
      return this;
    }

    /**
     * Configures the KijiURI with Zookeeper Quorum.
     *
     * @param zookeeperQuorum The zookeeper quorum.
     * @return This builder instance so you may chain configuration method calls.
     */
    public KijiURIBuilder withZookeeperQuorum(Iterable<String> zookeeperQuorum) {
      mZookeeperQuorum = ImmutableList.copyOf(zookeeperQuorum);
      return this;
    }

    /**
     * Configures the KijiURI with the Zookeeper client port.
     *
     * @param zookeeperClientPort The port.
     * @return This builder instance so you may chain configuration method calls.
     */
    public KijiURIBuilder withZookeeperClientPort(int zookeeperClientPort) {
      mZookeeperClientPort = zookeeperClientPort;
      return this;
    }

    /**
     * Configures the KijiURI with the Kiji instance name.
     *
     * @param instanceName The Kiji instance name.
     * @return This builder instance so you may chain configuration method calls.
     */
    public KijiURIBuilder withInstanceName(String instanceName) {
      mInstanceName = instanceName;
      return this;
    }

    /**
     * Configures the KijiURI with the Kiji table name.
     *
     * @param tableName The Kiji table name.
     * @return This builder instance so you may chain configuration method calls.
     */
    public KijiURIBuilder withTableName(String tableName) {
      mTableName = tableName;
      return this;
    }

    /**
     * Configures the KijiURI with the Kiji column names.
     *
     * @param columnNames The Kiji column names to configure.
     * @return This builder instance so you may chain configuration method calls.
     */
    public KijiURIBuilder withColumnNames(Collection<String> columnNames) {
      ImmutableList.Builder<KijiColumnName> builder = ImmutableList.builder();
      for (String column : columnNames) {
        builder.add(KijiColumnName.create(column));
      }
      mColumnNames = builder.build();
      return this;
    }

    /**
     * Adds the column names to the Kiji URI column names.
     *
     * @param columnNames The Kiji column names to add.
     * @return This builder instance so you may chain configuration method calls.
     */
    public KijiURIBuilder addColumnNames(Collection<KijiColumnName> columnNames) {
      ImmutableList.Builder<KijiColumnName> builder = ImmutableList.builder();
      builder.addAll(mColumnNames).addAll(columnNames);
      mColumnNames = builder.build();
      return this;
    }

    /**
     * Adds the column name to the Kiji URI column names.
     *
     * @param columnName The Kiji column name to add.
     * @return This builder instance so you may chain configuration method calls.
     */
    public KijiURIBuilder addColumnName(KijiColumnName columnName) {
      ImmutableList.Builder<KijiColumnName> builder = ImmutableList.builder();
      builder.addAll(mColumnNames).add(columnName);
      mColumnNames = builder.build();
      return this;
    }

    /**
     * Configures the KijiURI with the Kiji column names.
     *
     * @param columnNames The Kiji column names.
     * @return This builder instance so you may chain configuration method calls.
     */
    public KijiURIBuilder withColumnNames(Iterable<KijiColumnName> columnNames) {
      mColumnNames = ImmutableList.copyOf(columnNames);
      return this;
    }

    /**
     * Builds the configured KijiURI.
     *
     * @return A KijiURI.
     * @throws KijiURIException If the KijiURI was configured improperly.
     */
    public KijiURI build() {
      throw new UnsupportedOperationException("Abstract method.");
    }
  }

  /**
   * Gets a builder configured with default Kiji URI fields for an HBase cluster.
   *
   * More precisely, the following defaults are initialized:
   * <ul>
   *   <li>The Zookeeper quorum and client port is taken from the Hadoop <tt>Configuration</tt></li>
   *   <li>The Kiji instance name is set to <tt>KConstants.DEFAULT_INSTANCE_NAME</tt>
   *       (<tt>"default"</tt>).</li>
   *   <li>The table name and column names are explicitly left unset.</li>
   * </ul>
   *
   * @return A builder configured with defaults for an HBase cluster.
   */
  public static KijiURIBuilder newBuilder() {
    return new HBaseKijiURIBuilder();
  }

  /**
   * Gets a builder configured with a Kiji URI.
   *
   * @param uri The Kiji URI to configure the builder from.
   * @return A builder configured with uri.
   */
  public static KijiURIBuilder newBuilder(KijiURI uri) {
    return uri.getBuilder();
  }

  /**
   * Gets a builder configured with the Kiji URI.
   *
   * <p> The String parameter can be a relative URI (with a specified instance), in which
   *     case it is automatically normalized relative to DEFAULT_HBASE_URI.
   *
   * @param uri String specification of a Kiji URI.
   * @return A builder configured with uri.
   * @throws KijiURIException If the uri is invalid.
   */
  public static KijiURIBuilder newBuilder(final String uri) {
    final String uriWithScheme;
    if (RE_SCHEME.matcher(uri).matches()) {
      uriWithScheme = uri;
    } else {
      uriWithScheme = String.format("%s/%s/", KConstants.DEFAULT_HBASE_URI, uri);
    }
    try {
      return KijiURIParser.Factory.get(new URI(uriWithScheme));
    } catch (URISyntaxException exn) {
      throw new KijiURIException(uri, exn.getMessage());
    }
  }

  /**
   * Resolve the path relative to this KijiURI. Returns a new instance.
   *
   * @param path The path to resolve.
   * @return The resolved KijiURI.
   * @throws KijiURIException If this KijiURI is malformed.
   */
  public KijiURI resolve(String path) {
    try {
      // Without the "./", URI will assume a path containing a colon
      // is a new URI, for example "family:column".
      URI uri = new URI(toString()).resolve(String.format("./%s", path));
      return KijiURIParser.Factory.get(uri).build();
    } catch (URISyntaxException e) {
      throw new RuntimeException(
          String.format("KijiURI was incorrectly constructed (should never happen): %s",
              this.toString()));
    } catch (IllegalArgumentException e) {
      throw new KijiURIException(this.toString(),
          String.format("Path can not be resolved: %s", path));
    }
  }

  /**
   * Returns the address of each member of the ZooKeeper ensemble associated with this KijiURI
   * in comma-separated host:port  (standard ZooKeeper) format. This method will always return the
   * correct addresses of the ZooKeeper ensemble which hosts the metadata for this KijiURI's
   * instance.
   *
   * @return the addresses of the ZooKeeper ensemble members of the Kiji cluster.
   */
  public String getZooKeeperEnsemble() {
    return ZooKeeperFactory.Provider.get().getZooKeeperEnsemble(this);
  }

  /**
   * Returns the set of Zookeeper quorum hosts (names or IPs).
   *
   * <p> This method is not always guaranteed to return valid ZooKeeper hostnames, instead use
   *    {@link org.kiji.schema.KijiURI#getZooKeeperEnsemble()}. </p>
   *
   * <p> Host names or IP addresses are de-duplicated and sorted. </p>
   *
   * @return the set of Zookeeper quorum hosts (names or IPs).
   *     Never null.
   */
  public ImmutableList<String> getZookeeperQuorum() {
    return mZookeeperQuorumNormalized;
  }

  /**
   * Returns the original user-specified list of Zookeeper quorum hosts.
   *
   * <p> This method is not always guaranteed to return valid ZooKeeper hostnames, instead use
   *    {@link org.kiji.schema.KijiURI#getZooKeeperEnsemble()}. </p>
   *
   * <p> Host names are exactly as specified by the user. </p>
   *
   * @return the original user-specified list of Zookeeper quorum hosts.
   *     Never null.
   */
  public ImmutableList<String> getZookeeperQuorumOrdered() {
    return mZookeeperQuorum;
  }

  /** @return Zookeeper client port. */
  public int getZookeeperClientPort() {
    return mZookeeperClientPort;
  }

  /**
   * Returns the scheme of this KijiURI.
   *
   * @return the scheme of this KijiURI.
   */
  public String getScheme() {
    return mScheme;
  }

  /**
   * Returns the name of the Kiji instance specified by this URI, if any.
   *
   * @return the name of the Kiji instance specified by this URI.
   *     Null means unspecified (ie. this URI does not target a Kiji instance).
   */
  public String getInstance() {
    return mInstanceName;
  }

  /**
   * Returns the name of the Kiji table specified by this URI, if any.
   *
   * @return the name of the Kiji table specified by this URI.
   *     Null means unspecified (ie. this URI does not target a Kiji table).
   */
  public String getTable() {
    return mTableName;
  }

  /** @return Kiji columns (comma-separated list of Kiji column names), normalized. Never null. */
  public ImmutableList<KijiColumnName> getColumns() {
    return mColumnNamesNormalized;
  }

  /** @return Kiji columns (comma-separated list of Kiji column names), ordered. Never null. */
  public Collection<KijiColumnName> getColumnsOrdered() {
    return mColumnNames;
  }

  /** {@inheritDoc} */
  @Override
  public String toString() {
    return toString(false);
  }

  /**
   * Returns a string representation of this URI that preserves ordering of lists in fields,
   * such as the Zookeeper quorum and Kiji columns.
   *
   * @return An order-preserving string representation of this URI.
   */
  public String toOrderedString() {
    return toString(true);
  }

  /**
   * Returns a string representation of this URI.
   *
   * @param preserveOrdering Whether to preserve ordering of lsits in fields.
   * @return A string representation of this URI.
   */
  private String toString(boolean preserveOrdering) {
    // Remove trailing unset fields.
    if (!mColumnNames.isEmpty()) {
      return toStringCol(preserveOrdering);
    } else if (mTableName != null) {
      return toStringTable(preserveOrdering);
    } else if (mInstanceName != null) {
      return toStringInstance(preserveOrdering);
    } else {
      return toStringAuthority(preserveOrdering);
    }
  }

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

  /**
   * {@inheritDoc}
   *
   * *note* {@code KijiURI}'s are compared based on the string representation of the {@code URI}.
   * If two {@code KijiURI}s point to the same cluster with a different scheme, then they will
   * compare differently, for example {@code kiji://localhost} and {@code kiji-hbase://localhost}.
   */
  @Override
  public boolean equals(Object object) {
    if (object == null) {
      return false;
    }
    return object.getClass() == this.getClass() && object.toString().equals(this.toString());
  }

  /**
   * Validates the names used in the URI.
   *
   * @throws KijiURIException if there is an invalid name in this URI.
   */
  private void validateNames() {
    if ((mInstanceName != null) && !KijiNameValidator.isValidKijiName(mInstanceName)) {
      throw new KijiURIException(String.format(
          "Invalid Kiji URI: '%s' is not a valid Kiji instance name.", mInstanceName));
    }
    if ((mTableName != null) && !KijiNameValidator.isValidLayoutName(mTableName)) {
      throw new KijiURIException(String.format(
          "Invalid Kiji URI: '%s' is not a valid Kiji table name.", mTableName));
    }
  }

  /**
   * Appends the cluster identifier for this {@code KijiURI} to the passed in {@link StringBuilder}.
   *
   * This is a default implementation which will append the ZooKeeper ensemble to the string
   * builder.  May be overridden by subclasses if more than the ZooKeeper ensemble is necessary for
   * the cluster identifier.
   *
   * @param sb a StringBuilder to append the cluster identifier to.
   * @param preserveOrdering whether to preserve ordering in the cluster identifier components.
   * @return the StringBuilder with the cluster identifier appended.
   */
  protected StringBuilder appendClusterIdentifier(
      final StringBuilder sb,
      final boolean preserveOrdering
  ) {
    ImmutableList<String> zookeeperQuorum =
        preserveOrdering ? mZookeeperQuorum : mZookeeperQuorumNormalized;
    if (zookeeperQuorum == null) {
      sb.append(UNSET_URI_STRING);
    } else if (zookeeperQuorum.size() == 1) {
      sb.append(zookeeperQuorum.get(0));
    } else {
      sb.append('(');
      Joiner.on(',').appendTo(sb, zookeeperQuorum);
      sb.append(')');
    }
    sb
      .append(':')
      .append(mZookeeperClientPort)
      .append('/');

    return sb;
  }

  /**
   * Formats the full KijiURI up to the authority, preserving order.
   *
   * @param preserveOrdering Whether to preserve ordering.
   * @return Representation of this KijiURI up to the authority.
   */
  private String toStringAuthority(boolean preserveOrdering) {
    StringBuilder sb = new StringBuilder();
    sb.append(mScheme)
      .append("://");

    appendClusterIdentifier(sb, preserveOrdering);
    return sb.toString();
  }

  /**
   * Formats the full KijiURI up to the instance.
   *
   * @param preserveOrdering Whether to preserve ordering.
   * @return Representation of this KijiURI up to the instance.
   */
  private String toStringInstance(boolean preserveOrdering) {
    return String.format("%s%s/",
        toStringAuthority(preserveOrdering),
        (null == mInstanceName) ? UNSET_URI_STRING : mInstanceName);
  }

  /**
   * Formats the full KijiURI up to the table.
   *
   * @param preserveOrdering Whether to preserve ordering.
   * @return Representation of this KijiURI up to the table.
   */
  private String toStringTable(boolean preserveOrdering) {
    return String.format("%s%s/",
        toStringInstance(preserveOrdering),
        (null == mTableName) ? UNSET_URI_STRING : mTableName);
  }

  /**
   * Formats the full KijiURI up to the column.
   *
   * @param preserveOrdering Whether to preserve ordering.
   * @return Representation of this KijiURI up to the table.
   */
  private String toStringCol(boolean preserveOrdering) {
    String columnField;
    ImmutableList<KijiColumnName> columns =
        preserveOrdering ? mColumnNames : mColumnNamesNormalized;
    if (columns.isEmpty()) {
      columnField = UNSET_URI_STRING;
    } else {
      ImmutableList.Builder<String> builder = ImmutableList.builder();
      for (KijiColumnName column : columns) {
        builder.add(column.getName());
      }
      ImmutableList<String> strColumns = builder.build();
      if (strColumns.size() == 1) {
        columnField = strColumns.get(0);
      } else {
        columnField = Joiner.on(",").join(strColumns);
      }
    }

    try {
      // SCHEMA-6. URI Encode column names using RFC-2396.
      final URI columnsEncoded = new URI(KIJI_SCHEME, columnField, null);
      return String.format("%s%s/",
          toStringTable(preserveOrdering),
          columnsEncoded.getRawSchemeSpecificPart());
    } catch (URISyntaxException e) {
      throw new KijiURIException(e.getMessage());
    }
  }

  /**
   * Creates a builder with fields from this {@code KijiURI}.
   *
   * @return a builder with fields from this {@code KijiURI}.
   */
  protected KijiURIBuilder getBuilder() {
    throw new UnsupportedOperationException("Abstract method.");
  }

  /**
   * Returns a {@link KijiFactory} suitable for installing an instance of this {@code KijiURI}.
   *
   * {@code KijiURI} implementations are required to override this method to return a concrete
   * implementation of {@code KijiFactory} appropriate for the cluster type.
   *
   * @return a {@code KijiFactory} for this {@code KijiURI}.
   */
  protected KijiFactory getKijiFactory() {
    throw new UnsupportedOperationException("Abstract method.");
  }

  /**
   * Returns a {@link KijiFactory} suitable for installing an instance of this {@code KijiURI}.
   *
   * {@code KijiURI} implementations are required to override this method. Furthermore, the
   * overridden implementation is required to return a subclass of {@code KijiInstaller} which
   * has overridden implementations of
   * {@link KijiInstaller#install(KijiURI, org.kiji.schema.hbase.HBaseFactory, java.util.Map,
   * org.apache.hadoop.conf.Configuration)} and
   * {@link KijiInstaller#uninstall(KijiURI, org.kiji.schema.hbase.HBaseFactory,
   * org.apache.hadoop.conf.Configuration)}.
   *
   * @return a {@code KijiFactory} for this {@code KijiURI}.
   */
  protected KijiInstaller getKijiInstaller() {
    throw new UnsupportedOperationException("Abstract method.");
  }
}
TOP

Related Classes of org.kiji.schema.KijiURI

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.