Package org.kiji.schema.impl

Source Code of org.kiji.schema.impl.KijiURIParser$AuthorityParser

/**
* (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.impl;

import java.net.URI;
import java.util.List;
import java.util.regex.Matcher;

import com.google.common.base.CharMatcher;
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HConstants;

import org.kiji.annotations.ApiAudience;
import org.kiji.delegation.Lookups;
import org.kiji.delegation.NamedProvider;
import org.kiji.delegation.NoSuchProviderException;
import org.kiji.schema.KijiColumnName;
import org.kiji.schema.KijiURI;
import org.kiji.schema.KijiURI.KijiURIBuilder;
import org.kiji.schema.KijiURIException;
import org.kiji.schema.hbase.HBaseKijiURI;

/**
* A Parser for {@link KijiURI}s in text form.  {@code KijiURIParser}s register themselves to
* handle parsing of certain schemes, and the correct parser to use for a given string is decided
* by its scheme.
*/
@ApiAudience.Private
public interface KijiURIParser extends NamedProvider {
  /**
   * Parse a URI and return a {@link KijiURIBuilder}.
   *
   * @param uri to parse.
   * @return a KijiURIBuilder parsed from the URI.
   */
  KijiURIBuilder parse(URI uri);

  /**
   * A factory for retrieving a {@link KijiURIParser} for a URI, and parsing it.
   */
  public static class Factory {
    /**
     * Parse a {@link URI} into a {@link KijiURIBuilder} based on the {@link URI}'s scheme.
     *
     * @param uri to parse.
     * @return a {@link KijiURIBuilder} for the uri.
     */
    public static KijiURIBuilder get(URI uri) {
      String scheme = uri.getScheme();
      if (scheme.equals(KijiURI.KIJI_SCHEME)) {
        scheme = HBaseKijiURI.HBASE_SCHEME;
      }

      try {
        return Lookups.getNamed(KijiURIParser.class).lookup(scheme).parse(uri);
      } catch (NoSuchProviderException e) {
        throw new KijiURIException(
            uri.toString(),
            String.format("No parser available for Kiji scheme '%s'.", scheme));
      }
    }
  }


  /**
   * Class for parsing an authority portion in a KijiURI.
   *
   * An HBase KijiURI has only a single authority, whereas a Cassandra KijiURI has two, one for
   * ZooKeeper and another for Cassandra (the Cassandra KijiURI is not strictly a legal URI).
   *
   * The authority in a Cassandra KijiURI can also have a username and password.
   */
  public static final class AuthorityParser {
    private final ImmutableList<String> mHosts;
    private final Integer mHostPort;
    private final String mUsername;
    private final String mPassword;

    /**
     * Constructs an AuthorityParser.
     *
     * @param authority The authority within the URI.
     * @param uri The uri whose authority is to be parsed (used for generating messages in
     *     exceptions).
     * @return an {@code AuthorityParser} for the provided {@code URI}.
     * @throws KijiURIException If the authority is invalid.
     */
    public static AuthorityParser getAuthorityParser(String authority, URI uri) {
      return new AuthorityParser(authority, uri);
    }

    /**
     * Return a new authority parser, which will parse a substring of the entire URI.
     *
     * We specify the authority explicitly because in a Cassandra KijiURI, the Cassandra hosts
     * authority will be different from `uri.getAuthority()`.
     *
     * Parse the hosts from a host / port segment. The segment must be in one of the following
     * formats:
     *
     * <li> {@code host}
     * <li> {@code host:port}
     * <li> {@code host1,host2}
     * <li> {@code (host1,host2):port}
     * <li> {@code user@host}
     * <li> {@code user@host:port}
     * <li> {@code user@host1,host2}
     * <li> {@code user@(host1,host2):port}
     * <li> {@code user:password@host}
     * <li> {@code user:password@host:port}
     * <li> {@code user:password@host1,host2}
     * <li> {@code user:password@(host1,host2):port}
     *
     * @param authority The substring of the URI containing the authority.
     * @param uri The URI itself (needed here for error messages).
     */
    private AuthorityParser(String authority, URI uri) {
      // Extract the user info, if it is present.
      final String hostPortInfo = getHostAndPortInfoFromAuthority(uri, authority);
      final String userInfo = getUserInfoFromAuthority(uri, authority);

      mUsername = parseUsername(uri, userInfo);
      mPassword = parsePassword(uri, userInfo);

      // Get the hosts and ports.
      mHosts = parseHosts(uri, hostPortInfo);
      mHostPort = parsePort(uri, hostPortInfo);
    }

    /**
     * Extract the user information (username and password) from an authority.
     *
     * The returned value is of the form `username:password` or just `username`.
     *
     * @param uri The URI containing the authority (used to generate exception messages).
     * @param authority The authority to parse.
     * @return A string containing the user information, or null if the authority does not contain
     *     user information.
     */
    private static String getUserInfoFromAuthority(URI uri, String authority) {
      if (!authority.contains("@")) {
        return null;
      }
      // Should have no more than a single @ appear!
      final List<String> userInfoAndHostPortInfo =
          ImmutableList.copyOf(Splitter.on('@').split(authority));
      if (2 != userInfoAndHostPortInfo.size()) {
        throw new KijiURIException(
            uri.toString(), "Cannot have more than one '@' in URI authority");
      }
      return userInfoAndHostPortInfo.get(0);
    }

    /**
     * Extract the host(s) and port from an authority.
     *
     * The returned value is of the form `host`, `host:port`, `(host1,host2,...)`, or
     * `(host1,host2,...):port`.
     *
     * @param uri The URI containing the authority (used to generate exception messages).
     * @param authority The authority to parse.
     * @return A string containing the host(s) and optional port.
     */
    private static String getHostAndPortInfoFromAuthority(URI uri, String authority) {
      if (!authority.contains("@")) {
        return authority;
      }
      // Should have no more than a single @ appear!
      final List<String> userInfoAndHostPortInfo =
          ImmutableList.copyOf(Splitter.on('@').split(authority));
      if (2 != userInfoAndHostPortInfo.size()) {
        throw new KijiURIException(
            uri.toString(), "Cannot have more than one '@' in URI authority");
      }
      Preconditions.checkArgument(2 == userInfoAndHostPortInfo.size());
      return userInfoAndHostPortInfo.get(1);
    }

    /**
     * Extract the username from a user information string.
     *
     * @param uri The URI from which the user information comes (used for exception messages).
     * @param userInfo The user info, of the form `username` or `username:password` (can be null).
     * @return The username, or null if the `userInfo` is null.
     */
    private static String parseUsername(URI uri, String userInfo) {
      if (null == userInfo) {
        return null;
      }
      if (!userInfo.contains(":")) {
        return userInfo;
      }
      if (1 != CharMatcher.is(':').countIn(userInfo)) {
        throw new KijiURIException(
            uri.toString(), "Cannot have more than one ':' in URI user info");
      }
      final List<String> usernameAndPassword =
          ImmutableList.copyOf(Splitter.on(':').split(userInfo));
      Preconditions.checkArgument(2 == usernameAndPassword.size());
      return usernameAndPassword.get(0);
    }

    /**
     * Extract the password from a user information string.
     *
     * @param uri The URI from which the user information comes (used for exception messages).
     * @param userInfo The user info, of the form `username` or `username:password` (can be null).
     * @return The password, or null if it is not specified.
     */
    private static String parsePassword(URI uri, String userInfo) {
      if (null == userInfo) {
        return null;
      }
      if (!userInfo.contains(":")) {
        return null;
      }
      if (1 != CharMatcher.is(':').countIn(userInfo)) {
        throw new KijiURIException(
            uri.toString(), "Cannot have more than one ':' in URI user info");
      }
      final List<String> usernameAndPassword =
          ImmutableList.copyOf(Splitter.on(':').split(userInfo));
      Preconditions.checkArgument(2 == usernameAndPassword.size());
      return usernameAndPassword.get(1);
    }

    /**
     * Parse the hosts from a host / port segment. The segment must be in one of the following
     * formats:
     *
     * <li> {@code host}
     * <li> {@code host:port}
     * <li> {@code host1,host2}
     * <li> {@code (host1,host2):port}
     *
     * @param uri being parsed. Used for error messaging.
     * @param segment containing the host(s) and optionally the port.
     * @return list of hosts.
     */
    private static ImmutableList<String> parseHosts(URI uri, String segment) {
      final Matcher zkMatcher = KijiURI.RE_AUTHORITY_GROUP.matcher(segment);
      if (zkMatcher.matches()) {
        return ImmutableList.copyOf(Splitter.on(',').split(zkMatcher.group(1)));
      } else {
        final List<String> splits =
            ImmutableList.copyOf(Splitter.on(':').omitEmptyStrings().split(segment));
        switch (splits.size()) {
          case 1:
            return ImmutableList.copyOf(Splitter.on(',').split(segment));
          case 2:
            if (splits.get(0).contains(",")) {
              throw new KijiURIException(
                  uri.toString(), "Multiple ZooKeeper hosts must be parenthesized.");
            }
            return ImmutableList.of(splits.get(0));
          default:
            throw new KijiURIException(
                uri.toString(), "Invalid ZooKeeper ensemble cluster identifier.");
        }
      }
    }

    /**
     * Parse the port from a host / port segment. The segment must be in one of the following
     * formats:
     *
     * <li> {@code host}
     * <li> {@code host:port}
     * <li> {@code host1,host2}
     * <li> {@code (host1,host2):port}
     *
     * @param uri being parsed. Used for error messaging.
     * @param segment containing the host(s) and optionally the port.
     * @return the port, or {@code null} if no port is specified.
     */
    private static Integer parsePort(URI uri, String segment) {
      final List<String> parts = ImmutableList.copyOf(Splitter.on(':').split(segment));
      if (parts.size() != 2) {
        return null;
      }
      try {
        return Integer.parseInt(parts.get(1));
      } catch (NumberFormatException nfe) {
        throw new KijiURIException(uri.toString(),
            String.format("Can not parse port '%s'.", parts.get(1)));
      }
    }

    /**
     * @return the hosts from the parsed URI authority.
     */
    public ImmutableList<String> getHosts() {
      return mHosts;
    }

    /**
     * @return the host port from the parsed URI authority (can be null).
     */
    public Integer getHostPort() {
      return mHostPort;
    }

    /**
     * @return the username from the parsed URI authority (can be null).
     */
    public String getUsername() {
      return mUsername;
    }

    /**
     * @return the password from the parsed URI authority (can be null).
     */
    public String getPassword() {
      return mPassword;
    }
  }

  /**
   * Parser for the ZooKeeper authority section in a URI.
   */
  public static final class ZooKeeperAuthorityParser {
    /** ZooKeeper quorum configured from the local environment.*/
    public static final ImmutableList<String> ENV_ZOOKEEPER_QUORUM;

    /** ZooKeeper client port configured from the local environment. */
    public static final int ENV_ZOOKEEPER_CLIENT_PORT;

    /**
     * Resolves the local environment ZooKeeper parameters.
     *
     * Local environment refers to the hbase-site.xml configuration file available on the classpath.
     */
    static {
      Configuration conf = HBaseConfiguration.create();
      ENV_ZOOKEEPER_QUORUM = ImmutableList.copyOf(conf.get(HConstants.ZOOKEEPER_QUORUM).split(","));
      ENV_ZOOKEEPER_CLIENT_PORT =
          conf.getInt(HConstants.ZOOKEEPER_CLIENT_PORT, KijiURI.DEFAULT_ZOOKEEPER_CLIENT_PORT);
    }

    /** List of nodes in the ZooKeeper quorum for this authority. */
    private final ImmutableList<String> mZookeeperQuorum;

    /** The ZooKeeper port for this authority. */
    private final int mZookeeperClientPort;

    /**
     * Constructs an AuthorityParser.
     *
     * @param uri The uri whose authority is to be parsed.
     * @return an {@code AuthorityParser} for the provided {@code URI}.
     * @throws KijiURIException If the authority is invalid.
     */
    public static ZooKeeperAuthorityParser getAuthorityParser(URI uri) {
      return new ZooKeeperAuthorityParser(uri);
    }

    /**
     * Constructs an AuthorityParser for ZooKeeper authorities.
     *
     * @param uri The uri whose authority is to be parsed.
     * @throws KijiURIException If the authority is invalid.
     */
    private ZooKeeperAuthorityParser(URI uri) {
      final String authority = uri.getAuthority();
      if (null == authority) {
        throw new KijiURIException(uri.toString(), "ZooKeeper ensemble missing.");
      }

      if (authority.equals(KijiURI.ENV_URI_STRING)) {
        mZookeeperQuorum = ENV_ZOOKEEPER_QUORUM;
        mZookeeperClientPort = ENV_ZOOKEEPER_CLIENT_PORT;
      } else {
        final AuthorityParser authorityParser = AuthorityParser.getAuthorityParser(authority, uri);
        mZookeeperQuorum = authorityParser.getHosts();
        final Integer port = authorityParser.getHostPort();
        mZookeeperClientPort = port == null ? KijiURI.DEFAULT_ZOOKEEPER_CLIENT_PORT : port;
        Preconditions.checkArgument(null == authorityParser.getUsername());
        Preconditions.checkArgument(null == authorityParser.getPassword());
      }
    }

    /**
     * Gets the zookeeper quorum.
     *
     * @return The zookeeper quorum.
     */
    public ImmutableList<String> getZookeeperQuorum() {
      return mZookeeperQuorum;
    }

    /**
     * Gets the zookeeper client port.
     *
     * @return The zookeeper client port.
     */
    public int getZookeeperClientPort() {
      return mZookeeperClientPort;
    }
  }

  /**
   * Parses {@code URI} path segments into Kiji componenets.
   */
  public static class PathParser {

    private final String mInstance;
    private final String mTable;
    private final List<KijiColumnName> mColumns;

    /**
     * Create a new path segment parser for a KijiURI.
     *
     * @param uri to parse.
     */
    public PathParser(URI uri) {
      this(uri, 0);
    }

    /**
     * Create a new path segment parser for a KijiURI with the provided instanceIndex.  The Kiji
     * components begin at the {@code instanceIndex} offset of the path segments.
     *
     * @param uri to parse.
     * @param instanceIndex of Kiji component.
     */
    public PathParser(URI uri, int instanceIndex) {
      final List<String> segments =
          ImmutableList.copyOf(Splitter.on('/').omitEmptyStrings().split(uri.getPath()));
      final int size = segments.size();

      if (size - instanceIndex > 3) {
        throw new KijiURIException(uri.toString(), String.format("Too many path segments."));
      }
      final int tableIndex = instanceIndex + 1;
      final int columnsIndex = tableIndex + 1;

      if (size > instanceIndex  && !segments.get(instanceIndex).equals(KijiURI.UNSET_URI_STRING)) {
        mInstance = segments.get(instanceIndex);
      } else {
        mInstance = null;
      }

      if (size > tableIndex && !segments.get(tableIndex).equals(KijiURI.UNSET_URI_STRING)) {
        mTable = segments.get(tableIndex);
      } else {
        mTable = null;
      }

      if (size > columnsIndex && !segments.get(columnsIndex).equals(KijiURI.UNSET_URI_STRING)) {
        ImmutableList.Builder<KijiColumnName> columns = ImmutableList.builder();
        for (String column
            : Splitter.on(',').omitEmptyStrings().split(segments.get(columnsIndex))) {
          columns.add(KijiColumnName.create(column));
        }
        mColumns = columns.build();
      } else {
        mColumns = ImmutableList.of();
      }
    }

    /**
     * Get the parsed instance name.
     *
     * @return the instance name.
     */
    public String getInstance() {
      return mInstance;
    }

    /**
     * Get the parsed table name.
     *
     * @return the table name.
     */
    public String getTable() {
      return mTable;
    }

    /**
     * Get the column names.
     *
     * @return the column names.
     */
    public List<KijiColumnName> getColumns() {
      return mColumns;
    }
  }
}
TOP

Related Classes of org.kiji.schema.impl.KijiURIParser$AuthorityParser

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.
a href="/class/com/eviware/soapui/impl/wadl/inference/schema/content/EmptyContent.html" title="Examples of com.eviware.soapui.impl.wadl.inference.schema.content.EmptyContent">com.eviware.soapui.impl.wadl.inference.schema.content.EmptyContent
  • com.eviware.soapui.impl.wadl.inference.schema.particles.AttributeParticle
  • com.eviware.soapui.impl.wadl.inference.schema.particles.ElementParticle
  • 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.