View Javadoc

1   /**
2    * Copyright 2007 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase;
21  
22  import java.io.DataInput;
23  import java.io.DataOutput;
24  import java.io.IOException;
25  import java.net.InetAddress;
26  import java.net.InetSocketAddress;
27  
28  import org.apache.commons.logging.LogFactory;
29  import org.apache.hadoop.io.WritableComparable;
30  
31  /**
32   * HServerAddress hosts a {@link InetSocketAddress} and makes it
33   * {@link WritableComparable}.  Resolves on construction AND on
34   * deserialization -- since we're internally creating an InetSocketAddress --
35   * so could end up with different results if the two ends of serialization have
36   * different resolvers. Be careful where you use it.  Should only be used when
37   * you need to pass an InetSocketAddress across an RPC.  Even then its a bad
38   * idea because of the above resolve issue.
39   * @deprecated Use {@link InetSocketAddress} or {@link ServerName} or
40   * a hostname String and port.
41   */
42  public class HServerAddress implements WritableComparable<HServerAddress> {
43    // Hard to deprecate this class. Its in the API as internal class,
44    // in particular as an inner class of HRegionLocation.  Besides, sometimes
45    // we do want to serialize a InetSocketAddress; this class can be used then.
46    private InetSocketAddress address = null;
47    private String cachedToString = "";
48  
49    /**
50     * Constructor for deserialization use only.
51     */
52    public HServerAddress() {
53      super();
54    }
55  
56    /**
57     * Construct an instance from an {@link InetSocketAddress}.
58     * @param address InetSocketAddress of server
59     */
60    public HServerAddress(InetSocketAddress address) {
61      this.address = address;
62      checkBindAddressCanBeResolved();
63      this.cachedToString = createCachedToString();
64    }
65  
66    private String createCachedToString() {
67      return this.address.toString();
68    }
69  
70    /**
71     * @param hostname Hostname
72     * @param port Port number
73     */
74    public HServerAddress(final String hostname, final int port) {
75      this(getResolvedAddress(new InetSocketAddress(hostname, port)));
76    }
77  
78    /**
79     * Copy-constructor.
80     * @param other HServerAddress to copy from
81     */
82    public HServerAddress(HServerAddress other) {
83      this(getResolvedAddress(new InetSocketAddress(other.getHostname(), other.getPort())));
84    }
85  
86     private static InetSocketAddress getResolvedAddress(InetSocketAddress address) {
87       String bindAddress = getBindAddressInternal(address);
88       int port = address.getPort();
89       return new InetSocketAddress(bindAddress, port);
90     }
91    
92    /** @return Bind address -- the raw IP, the result of a call to
93     * InetSocketAddress#getAddress()#getHostAddress() --
94     * or null if cannot resolve */
95    public String getBindAddress() {
96      return getBindAddressInternal(address);
97    }
98  
99    private static String getBindAddressInternal(InetSocketAddress address) {
100     final InetAddress addr = address.getAddress();
101     if (addr != null) {
102       return addr.getHostAddress();
103     } else {
104       LogFactory.getLog(HServerAddress.class).error("Could not resolve the"
105           + " DNS name of " + address.getHostName());
106       return null;
107     }
108   }
109   
110   private void checkBindAddressCanBeResolved() {
111     if (getBindAddress() == null) {
112       throw new IllegalArgumentException("Could not resolve the"
113           + " DNS name of " + this.address.toString());
114     }
115   }
116 
117   /** @return Port number */
118   public int getPort() {
119     return this.address.getPort();
120   }
121 
122   /** @return Hostname */
123   public String getHostname() {
124     // Kerberos is case-sensitive, and dictates that, where hostnames are
125     // case-insensitive (as in DNS), the lowercase version must be used
126     // So here we lowercase to properly interact with kerberos auth
127     return this.address.getHostName().toLowerCase();
128   }
129 
130   /**
131    * @return Returns <hostname> ':' <port>
132    */
133   public String getHostnameAndPort() {
134     return getHostname() + ":" + getPort();
135   }
136 
137   /** @return The InetSocketAddress */
138   public InetSocketAddress getInetSocketAddress() {
139     return this.address;
140   }
141 
142   /**
143    * @return String formatted as <code>&lt;bind address> ':' &lt;port></code>
144    */
145   @Override
146   public String toString() {
147     return this.cachedToString;
148   }
149 
150   @Override
151   public boolean equals(Object o) {
152     if (this == o) return true;
153     if (o == null) return false;
154     if (getClass() != o.getClass()) return false;
155     return compareTo((HServerAddress)o) == 0;
156   }
157 
158   @Override
159   public int hashCode() {
160     int result = address == null? 0: address.hashCode();
161     result ^= toString().hashCode();
162     return result;
163   }
164 
165   //
166   // Writable
167   //
168 
169   public void readFields(DataInput in) throws IOException {
170     String hostname = in.readUTF();
171     int port = in.readInt();
172     if (hostname != null && hostname.length() > 0) {
173       this.address = getResolvedAddress(new InetSocketAddress(hostname, port));
174       checkBindAddressCanBeResolved();
175       createCachedToString();
176     }
177   }
178 
179   public void write(DataOutput out) throws IOException {
180     if (this.address == null) {
181       out.writeUTF("");
182       out.writeInt(0);
183     } else {
184       out.writeUTF(this.address.getAddress().getHostName());
185       out.writeInt(this.address.getPort());
186     }
187   }
188 
189   //
190   // Comparable
191   //
192 
193   public int compareTo(HServerAddress o) {
194     // Addresses as Strings may not compare though address is for the one
195     // server with only difference being that one address has hostname
196     // resolved whereas other only has IP.
197     if (this.address.equals(o.address)) return 0;
198     return toString().compareTo(o.toString());
199   }
200 }