/** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.hadoop.hbase; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.io.WritableComparable; /** * HServerAddress hosts a {@link InetSocketAddress} and makes it * {@link WritableComparable}. Resolves on construction AND on * deserialization -- since we're internally creating an InetSocketAddress -- * so could end up with different results if the two ends of serialization have * different resolvers. Be careful where you use it. Should only be used when * you need to pass an InetSocketAddress across an RPC. Even then its a bad * idea because of the above resolve issue. * @deprecated Use {@link InetSocketAddress} or {@link ServerName} or * a hostname String and port. */ public class HServerAddress implements WritableComparable<HServerAddress> { // Hard to deprecate this class. Its in the API as internal class, // in particular as an inner class of HRegionLocation. Besides, sometimes // we do want to serialize a InetSocketAddress; this class can be used then. private InetSocketAddress address = null; private String cachedToString = ""; /** * Constructor for deserialization use only. */ public HServerAddress() { super(); } /** * Construct an instance from an {@link InetSocketAddress}. * @param address InetSocketAddress of server */ public HServerAddress(InetSocketAddress address) { this.address = address; checkBindAddressCanBeResolved(); this.cachedToString = createCachedToString(); } private String createCachedToString() { return this.address.toString(); } /** * @param hostname Hostname * @param port Port number */ public HServerAddress(final String hostname, final int port) { this(getResolvedAddress(new InetSocketAddress(hostname, port))); } /** * Copy-constructor. * @param other HServerAddress to copy from */ public HServerAddress(HServerAddress other) { this(getResolvedAddress(new InetSocketAddress(other.getHostname(), other.getPort()))); } private static InetSocketAddress getResolvedAddress(InetSocketAddress address) { String bindAddress = getBindAddressInternal(address); int port = address.getPort(); return new InetSocketAddress(bindAddress, port); } /** @return Bind address -- the raw IP, the result of a call to * InetSocketAddress#getAddress()#getHostAddress() -- * or null if cannot resolve */ public String getBindAddress() { return getBindAddressInternal(address); } private static String getBindAddressInternal(InetSocketAddress address) { final InetAddress addr = address.getAddress(); if (addr != null) { return addr.getHostAddress(); } else { LogFactory.getLog(HServerAddress.class).error("Could not resolve the" + " DNS name of " + address.getHostName()); return null; } } private void checkBindAddressCanBeResolved() { if (getBindAddress() == null) { throw new IllegalArgumentException("Could not resolve the" + " DNS name of " + this.address.toString()); } } /** @return Port number */ public int getPort() { return this.address.getPort(); } /** @return Hostname */ public String getHostname() { // Kerberos is case-sensitive, and dictates that, where hostnames are // case-insensitive (as in DNS), the lowercase version must be used // So here we lowercase to properly interact with kerberos auth return this.address.getHostName().toLowerCase(); } /** * @return Returns <hostname> ':' <port> */ public String getHostnameAndPort() { return getHostname() + ":" + getPort(); } /** @return The InetSocketAddress */ public InetSocketAddress getInetSocketAddress() { return this.address; } /** * @return String formatted as <code><bind address> ':' <port></code> */ @Override public String toString() { return this.cachedToString; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null) return false; if (getClass() != o.getClass()) return false; return compareTo((HServerAddress)o) == 0; } @Override public int hashCode() { int result = address == null? 0: address.hashCode(); result ^= toString().hashCode(); return result; } // // Writable // public void readFields(DataInput in) throws IOException { String hostname = in.readUTF(); int port = in.readInt(); if (hostname != null && hostname.length() > 0) { this.address = getResolvedAddress(new InetSocketAddress(hostname, port)); checkBindAddressCanBeResolved(); createCachedToString(); } } public void write(DataOutput out) throws IOException { if (this.address == null) { out.writeUTF(""); out.writeInt(0); } else { out.writeUTF(this.address.getAddress().getHostName()); out.writeInt(this.address.getPort()); } } // // Comparable // public int compareTo(HServerAddress o) { // Addresses as Strings may not compare though address is for the one // server with only difference being that one address has hostname // resolved whereas other only has IP. if (this.address.equals(o.address)) return 0; return toString().compareTo(o.toString()); } }