/**
* (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.");
}
}