001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019package org.apache.hadoop.registry.client.binding; 020 021import com.google.common.base.Preconditions; 022import org.apache.hadoop.classification.InterfaceAudience; 023import org.apache.hadoop.classification.InterfaceStability; 024import org.apache.hadoop.registry.client.exceptions.InvalidRecordException; 025import static org.apache.hadoop.registry.client.types.AddressTypes.*; 026import org.apache.hadoop.registry.client.types.Endpoint; 027import org.apache.hadoop.registry.client.types.ProtocolTypes; 028import org.apache.hadoop.registry.client.types.ServiceRecord; 029 030import java.net.InetSocketAddress; 031import java.net.MalformedURLException; 032import java.net.URI; 033import java.net.URL; 034import java.util.ArrayList; 035import java.util.HashMap; 036import java.util.List; 037import java.util.Map; 038 039/** 040 * Static methods to work with registry types —primarily endpoints and the 041 * list representation of addresses. 042 */ 043@InterfaceAudience.Public 044@InterfaceStability.Evolving 045public class RegistryTypeUtils { 046 047 /** 048 * Create a URL endpoint from a list of URIs 049 * @param api implemented API 050 * @param protocolType protocol type 051 * @param uris URIs 052 * @return a new endpoint 053 */ 054 public static Endpoint urlEndpoint(String api, 055 String protocolType, 056 URI... uris) { 057 return new Endpoint(api, protocolType, uris); 058 } 059 060 /** 061 * Create a REST endpoint from a list of URIs 062 * @param api implemented API 063 * @param uris URIs 064 * @return a new endpoint 065 */ 066 public static Endpoint restEndpoint(String api, 067 URI... uris) { 068 return urlEndpoint(api, ProtocolTypes.PROTOCOL_REST, uris); 069 } 070 071 /** 072 * Create a Web UI endpoint from a list of URIs 073 * @param api implemented API 074 * @param uris URIs 075 * @return a new endpoint 076 */ 077 public static Endpoint webEndpoint(String api, 078 URI... uris) { 079 return urlEndpoint(api, ProtocolTypes.PROTOCOL_WEBUI, uris); 080 } 081 082 /** 083 * Create an internet address endpoint from a list of URIs 084 * @param api implemented API 085 * @param protocolType protocol type 086 * @param hostname hostname/FQDN 087 * @param port port 088 * @return a new endpoint 089 */ 090 091 public static Endpoint inetAddrEndpoint(String api, 092 String protocolType, 093 String hostname, 094 int port) { 095 Preconditions.checkArgument(api != null, "null API"); 096 Preconditions.checkArgument(protocolType != null, "null protocolType"); 097 Preconditions.checkArgument(hostname != null, "null hostname"); 098 return new Endpoint(api, 099 ADDRESS_HOSTNAME_AND_PORT, 100 protocolType, 101 hostnamePortPair(hostname, port)); 102 } 103 104 /** 105 * Create an IPC endpoint 106 * @param api API 107 * @param address the address as a tuple of (hostname, port) 108 * @return the new endpoint 109 */ 110 public static Endpoint ipcEndpoint(String api, InetSocketAddress address) { 111 return new Endpoint(api, 112 ADDRESS_HOSTNAME_AND_PORT, 113 ProtocolTypes.PROTOCOL_HADOOP_IPC, 114 address== null ? null: hostnamePortPair(address)); 115 } 116 117 /** 118 * Create a single entry map 119 * @param key map entry key 120 * @param val map entry value 121 * @return a 1 entry map. 122 */ 123 public static Map<String, String> map(String key, String val) { 124 Map<String, String> map = new HashMap<String, String>(1); 125 map.put(key, val); 126 return map; 127 } 128 129 /** 130 * Create a URI 131 * @param uri value 132 * @return a 1 entry map. 133 */ 134 public static Map<String, String> uri(String uri) { 135 return map(ADDRESS_URI, uri); 136 } 137 138 /** 139 * Create a (hostname, port) address pair 140 * @param hostname hostname 141 * @param port port 142 * @return a 1 entry map. 143 */ 144 public static Map<String, String> hostnamePortPair(String hostname, int port) { 145 Map<String, String> map = 146 map(ADDRESS_HOSTNAME_FIELD, hostname); 147 map.put(ADDRESS_PORT_FIELD, Integer.toString(port)); 148 return map; 149 } 150 151 /** 152 * Create a (hostname, port) address pair 153 * @param address socket address whose hostname and port are used for the 154 * generated address. 155 * @return a 1 entry map. 156 */ 157 public static Map<String, String> hostnamePortPair(InetSocketAddress address) { 158 return hostnamePortPair(address.getHostName(), address.getPort()); 159 } 160 161 /** 162 * Require a specific address type on an endpoint 163 * @param required required type 164 * @param epr endpoint 165 * @throws InvalidRecordException if the type is wrong 166 */ 167 public static void requireAddressType(String required, Endpoint epr) throws 168 InvalidRecordException { 169 if (!required.equals(epr.addressType)) { 170 throw new InvalidRecordException( 171 epr.toString(), 172 "Address type of " + epr.addressType 173 + " does not match required type of " 174 + required); 175 } 176 } 177 178 /** 179 * Get a single URI endpoint 180 * @param epr endpoint 181 * @return the uri of the first entry in the address list. Null if the endpoint 182 * itself is null 183 * @throws InvalidRecordException if the type is wrong, there are no addresses 184 * or the payload ill-formatted 185 */ 186 public static List<String> retrieveAddressesUriType(Endpoint epr) 187 throws InvalidRecordException { 188 if (epr == null) { 189 return null; 190 } 191 requireAddressType(ADDRESS_URI, epr); 192 List<Map<String, String>> addresses = epr.addresses; 193 if (addresses.size() < 1) { 194 throw new InvalidRecordException(epr.toString(), 195 "No addresses in endpoint"); 196 } 197 List<String> results = new ArrayList<String>(addresses.size()); 198 for (Map<String, String> address : addresses) { 199 results.add(getAddressField(address, ADDRESS_URI)); 200 } 201 return results; 202 } 203 204 /** 205 * Get a specific field from an address -raising an exception if 206 * the field is not present 207 * @param address address to query 208 * @param field field to resolve 209 * @return the resolved value. Guaranteed to be non-null. 210 * @throws InvalidRecordException if the field did not resolve 211 */ 212 public static String getAddressField(Map<String, String> address, 213 String field) throws InvalidRecordException { 214 String val = address.get(field); 215 if (val == null) { 216 throw new InvalidRecordException("", "Missing address field: " + field); 217 } 218 return val; 219 } 220 221 /** 222 * Get the address URLs. Guranteed to return at least one address. 223 * @param epr endpoint 224 * @return the address as a URL 225 * @throws InvalidRecordException if the type is wrong, there are no addresses 226 * or the payload ill-formatted 227 * @throws MalformedURLException address can't be turned into a URL 228 */ 229 public static List<URL> retrieveAddressURLs(Endpoint epr) 230 throws InvalidRecordException, MalformedURLException { 231 if (epr == null) { 232 throw new InvalidRecordException("", "Null endpoint"); 233 } 234 List<String> addresses = retrieveAddressesUriType(epr); 235 List<URL> results = new ArrayList<URL>(addresses.size()); 236 for (String address : addresses) { 237 results.add(new URL(address)); 238 } 239 return results; 240 } 241 242 /** 243 * Validate the record by checking for null fields and other invalid 244 * conditions 245 * @param path path for exceptions 246 * @param record record to validate. May be null 247 * @throws InvalidRecordException on invalid entries 248 */ 249 public static void validateServiceRecord(String path, ServiceRecord record) 250 throws InvalidRecordException { 251 if (record == null) { 252 throw new InvalidRecordException(path, "Null record"); 253 } 254 if (!ServiceRecord.RECORD_TYPE.equals(record.type)) { 255 throw new InvalidRecordException(path, 256 "invalid record type field: \"" + record.type + "\""); 257 } 258 259 if (record.external != null) { 260 for (Endpoint endpoint : record.external) { 261 validateEndpoint(path, endpoint); 262 } 263 } 264 if (record.internal != null) { 265 for (Endpoint endpoint : record.internal) { 266 validateEndpoint(path, endpoint); 267 } 268 } 269 } 270 271 /** 272 * Validate the endpoint by checking for null fields and other invalid 273 * conditions 274 * @param path path for exceptions 275 * @param endpoint endpoint to validate. May be null 276 * @throws InvalidRecordException on invalid entries 277 */ 278 public static void validateEndpoint(String path, Endpoint endpoint) 279 throws InvalidRecordException { 280 if (endpoint == null) { 281 throw new InvalidRecordException(path, "Null endpoint"); 282 } 283 try { 284 endpoint.validate(); 285 } catch (RuntimeException e) { 286 throw new InvalidRecordException(path, e.toString()); 287 } 288 } 289 290}