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
019 package org.apache.hadoop.registry.client.binding;
020
021 import com.google.common.base.Preconditions;
022 import org.apache.hadoop.classification.InterfaceAudience;
023 import org.apache.hadoop.classification.InterfaceStability;
024 import org.apache.hadoop.registry.client.exceptions.InvalidRecordException;
025 import static org.apache.hadoop.registry.client.types.AddressTypes.*;
026 import org.apache.hadoop.registry.client.types.Endpoint;
027 import org.apache.hadoop.registry.client.types.ProtocolTypes;
028 import org.apache.hadoop.registry.client.types.ServiceRecord;
029
030 import java.net.InetSocketAddress;
031 import java.net.MalformedURLException;
032 import java.net.URI;
033 import java.net.URL;
034 import java.util.ArrayList;
035 import java.util.HashMap;
036 import java.util.List;
037 import 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
045 public 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 }