1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 package org.apache.river.discovery; 20 21 import java.io.IOException; 22 import java.net.DatagramPacket; 23 import java.net.Socket; 24 import java.security.AccessController; 25 import java.security.PrivilegedAction; 26 import java.util.Collection; 27 import java.util.Iterator; 28 import java.util.ServiceLoader; 29 import java.util.logging.Level; 30 import java.util.logging.Logger; 31 import net.jini.core.constraint.InvocationConstraints; 32 import net.jini.io.UnsupportedConstraintException; 33 34 /** 35 * <p> 36 * Class providing methods for participating in versions 1 and 2 of the 37 * discovery protocol. </p> 38 * 39 * <b>Logging</b> 40 * <p> 41 * 42 * This implementation uses the {@link java.util.logging.Logger}s named 43 * <code>org.apache.river.discovery.DiscoveryV1</code> and 44 * <code>org.apache.river.discovery.DiscoveryV2</code> to log information at the 45 * following logging levels: </p> 46 * 47 * <table border="1" cellpadding="5" 48 * summary="Describes logging performed by the 49 * Discovery class to the DiscoveryV1 logger at various 50 * logging levels"> 51 * 52 * <caption><b><code>org.apache.river.discovery.DiscoveryV1</code></b></caption> 53 * 54 * <tr> <th scope="col"> Level <th scope="col"> Description 55 * 56 * <tr> <td> {@link java.util.logging.Level#FINEST FINEST} 57 * <td> Encoding and decoding of discovery protocol version 1 multicast 58 * requests, multicast announcements, and unicast responses 59 * 60 * </table> 61 * 62 * <table border="1" cellpadding="5" 63 * summary="Describes logging performed by the 64 * Discovery class to the DiscoveryV2 logger at various logging 65 * levels"> 66 * 67 * <caption><b><code>org.apache.river.discovery.DiscoveryV2</code></b></caption> 68 * 69 * <tr> <th scope="col"> Level <th scope="col"> Description 70 * 71 * <tr> <td> {@link java.util.logging.Level#WARNING WARNING} 72 * <td> Truncation of unicast request format ID list due to length; 73 * discovery format providers that are unusable or have conflicting 74 * discovery format IDs 75 * 76 * <tr> <td> {@link org.apache.river.logging.Levels#HANDLED HANDLED} 77 * <td> Constraint check failures encountered during the unicast discovery 78 * handshake when determining a suitable discovery format to use 79 * 80 * <tr> <td> {@link java.util.logging.Level#FINEST FINEST} 81 * <td> Encoding and decoding of discovery protocol version 2 multicast 82 * requests, multicast announcements, and unicast responses; also, 83 * access of <code>Discovery</code> instances implementing protocol 84 * version 2 85 * 86 * </table> 87 * 88 * @author Sun Microsystems, Inc. 89 * @since 2.0 90 */ 91 public abstract class Discovery { 92 93 /** The version number for discovery protocol version 1. */ 94 public static final int PROTOCOL_VERSION_1 = 1; 95 96 /** The version number for discovery protocol version 2. */ 97 public static final int PROTOCOL_VERSION_2 = 2; 98 99 static final int MIN_MAX_PACKET_SIZE = 512; 100 101 private static Logger logger = Logger.getLogger(Discovery.class.getCanonicalName()); 102 /** 103 * Returns an instance implementing protocol version 1. 104 * 105 * @return an instance implementing protocol version 1 106 */ 107 public static Discovery getProtocol1() { 108 return DiscoveryV1.getInstance(); 109 } 110 111 /** 112 * Returns an instance implementing protocol version 2 which uses providers 113 * loaded from the given class loader, or the current context class loader 114 * if the given loader is <code>null</code>. Available providers are 115 * determined by interpreting any resources of the indicated class loader 116 * named 117 * <code>"META-INF/services/org.apache.river.discovery.DiscoveryFormatProvider"</code> 118 * as files containing names of provider classes, with one name per line. 119 * 120 * @param loader class loader from which to load providers, or 121 * <code>null</code> to indicate the current context class loader 122 * @return an instance implementing protocol version 2 123 */ 124 public static Discovery getProtocol2(ClassLoader loader) { 125 return DiscoveryV2.getInstance(loader); 126 } 127 128 /** 129 * Returns an instance implementing protocol version 2 which uses the given 130 * providers. Contents of arrays are copied; <code>null</code> array 131 * values are equivalent to empty arrays. 132 * 133 * @param mre providers for encoding multicast requests 134 * @param mrd providers for decoding multicast requests 135 * @param mae providers for encoding multicast announcements 136 * @param mad providers for decoding multicast announcements 137 * @param udc providers for performing the client side of unicast discovery 138 * @param uds providers for performing the server side of unicast discovery 139 * @return an instance implementing protocol version 2 140 */ 141 public static Discovery getProtocol2(MulticastRequestEncoder[] mre, 142 MulticastRequestDecoder[] mrd, 143 MulticastAnnouncementEncoder[] mae, 144 MulticastAnnouncementDecoder[] mad, 145 UnicastDiscoveryClient[] udc, 146 UnicastDiscoveryServer[] uds) 147 { 148 return DiscoveryV2.getInstance(mre, mrd, mae, mad, udc, uds); 149 } 150 151 /** 152 * Returns an instance implementing the unicast https protocol which uses providers 153 * loaded from the given class loader, or the context class loader 154 * if the given loader is <code>null</code>. Available providers are 155 * determined by interpreting any resources of the indicated class loader 156 * named 157 * <code>"META-INF/services/org.apache.river.discovery.Discovery"</code> 158 * with a toString() method that returns the string "UnicastHTTPS". 159 * 160 * TODO: provide a mechanism to allow more flexible mechanism for selection 161 * of loader. 162 * 163 * @param loader class loader from which to load providers, or 164 * <code>null</code> to indicate the current context class loader 165 * @return an instance implementing the unicast https protocol 166 */ 167 public static Discovery getUnicastHttps(final ClassLoader loader){ 168 return AccessController.doPrivileged( 169 new PrivilegedAction<Discovery>(){ 170 @Override 171 public Discovery run() { 172 ClassLoader ploader; 173 if (loader == null){ 174 ploader = Thread.currentThread().getContextClassLoader(); 175 } else { 176 ploader = loader; 177 } 178 ServiceLoader<Discovery> serviceLoader 179 = ServiceLoader.load(Discovery.class, ploader); 180 Iterator<Discovery> iter = serviceLoader.iterator(); 181 Discovery spi; 182 try { 183 while ( iter.hasNext() ) { 184 try { 185 spi = iter.next(); 186 if (spi != null && spi.toString().equals("UnicastHTTPS")) { 187 logger.log(Level.CONFIG, "loaded: {0}", spi.getClass().getName()); 188 return spi; 189 } 190 } catch (Throwable e) { 191 logger.log( 192 Level.CONFIG, 193 "error loading Discovery: {0}", 194 new Object[]{e} 195 ); 196 } 197 } 198 } catch (Throwable t) { } 199 logger.log(Level.CONFIG, "uable to find Discovery Provider"); 200 return null; 201 } 202 }); 203 } 204 205 /** 206 * Returns an iterator which can be used to encode the given multicast 207 * request data into sets of {@link DatagramPacket}s, each bounded in 208 * length by the specified maximum packet size, in a manner that satisfies 209 * the given constraints. <code>null</code> constraints are considered 210 * equivalent to empty constraints. The destination of each 211 * <code>DatagramPacket</code> produced by the returned iterator is set to 212 * the address returned by 213 * {@link net.jini.discovery.Constants#getRequestAddress}, with the value 214 * of {@link net.jini.discovery.Constants#discoveryPort} used as the 215 * destination port. 216 * 217 * @param request the request data to encode 218 * @param maxPacketSize the maximum size of packets to produce 219 * @param constraints the constraints to apply when encoding the data, or 220 * <code>null</code> 221 * @return an iterator to use for encoding the data 222 * @throws NullPointerException if <code>request</code> is 223 * <code>null</code> 224 */ 225 public abstract EncodeIterator encodeMulticastRequest( 226 MulticastRequest request, 227 int maxPacketSize, 228 InvocationConstraints constraints); 229 230 /** 231 * Decodes the multicast request data contained in the given datagram in a 232 * manner that satisfies the specified constraints and client subject 233 * checker (if any), returning a {@link MulticastRequest} instance that 234 * contains the decoded data. <code>null</code> constraints are considered 235 * equivalent to empty constraints. All the specified constraints are 236 * checked before this method returns. 237 * 238 * @param packet the packet to decode 239 * @param constraints the constraints to apply when decoding the packet, or 240 * <code>null</code> 241 * @param checker the object to use to check the client subject, or 242 * <code>null</code> 243 * @return the decoded multicast request data 244 * @throws IOException if an error occurs in interpreting the data 245 * @throws UnsupportedConstraintException if unable to satisfy the 246 * specified constraints 247 * @throws SecurityException if the given constraints cannot be satisfied 248 * due to insufficient caller permissions, or if the client subject check 249 * fails 250 * @throws NullPointerException if <code>packet</code> is <code>null</code> 251 */ 252 public abstract MulticastRequest decodeMulticastRequest( 253 DatagramPacket packet, 254 InvocationConstraints constraints, 255 ClientSubjectChecker checker) 256 throws IOException; 257 258 /** 259 * Decodes the multicast request data contained in the given datagram in a 260 * manner that satisfies the specified constraints and client subject 261 * checker (if any), returning a {@link MulticastRequest} instance that 262 * contains the decoded data, with constraint checking optionally 263 * delayed. <code>null</code> constraints are considered 264 * equivalent to empty constraints. 265 * <p>The <code>delayConstraintCheck</code> flag is used to control delayed 266 * constraint checking. Delayed constraint checking is useful for 267 * potentially delaying the expense of complete constraint checking, until 268 * other checks have been made on the returned 269 * <code>MulticastRequest</code> for preliminary validation. 270 * Implementations may ignore the flag, in which case, the behavior is 271 * equivalent to that of {@link 272 * Discovery#decodeMulticastRequest(DatagramPacket, InvocationConstraints, 273 * ClientSubjectChecker) decodeMulticastRequest}. 274 * <p>If <code>delayConstraintCheck</code> is <code>true</code>, the method 275 * behaves as follows:<ul> 276 * <li> Some of the specified constraints may not be checked before this 277 * method returns; the returned <code>MulticastRequest</code>'s 278 * {@link MulticastRequest#checkConstraints checkConstraints} 279 * method must be invoked to complete checking of all the constraints. 280 * <li> Constraints which must be checked before accessor methods of the 281 * returned <code>MulticastRequest</code> can be invoked are always 282 * checked before this method returns.</ul> 283 * <p>If <code>delayConstraintCheck</code> is <code>false</code>, all the 284 * specified constraints are checked before this method returns. 285 * <p><code>Discovery</code> implements this method to simply invoke {@link 286 * Discovery#decodeMulticastRequest(DatagramPacket, InvocationConstraints, 287 * ClientSubjectChecker) decodeMulticastRequest}, and thus checks all the 288 * specified constraints before returning. 289 * 290 * @param packet the packet to decode 291 * @param constraints the constraints to apply when decoding the packet, or 292 * <code>null</code> 293 * @param checker the object to use to check the client subject, or 294 * <code>null</code> 295 * @param delayConstraintCheck flag to control delayed constraint checking 296 * @return the decoded multicast request data. 297 * @throws IOException if an error occurs in interpreting the data 298 * @throws SecurityException if the given constraints cannot be satisfied 299 * due to insufficient caller permissions, or if the client subject check 300 * fails 301 * @throws NullPointerException if <code>packet</code> is <code>null</code> 302 * @since 2.1 303 */ 304 public MulticastRequest decodeMulticastRequest( 305 DatagramPacket packet, 306 InvocationConstraints constraints, 307 ClientSubjectChecker checker, 308 boolean delayConstraintCheck) 309 throws IOException 310 { 311 return decodeMulticastRequest(packet, constraints, checker); 312 } 313 314 /** 315 * Returns an iterator which can be used to encode the given multicast 316 * announcement data into sets of {@link DatagramPacket}s, each bounded in 317 * length by the specified maximum packet size, in a manner that satisfies 318 * the given constraints. <code>null</code> constraints are considered 319 * equivalent to empty constraints. The destination of each 320 * <code>DatagramPacket</code> produced by the returned iterator is set to 321 * the address returned by 322 * {@link net.jini.discovery.Constants#getAnnouncementAddress}, with the 323 * value of {@link net.jini.discovery.Constants#discoveryPort} used as the 324 * destination port. 325 * 326 * @param announcement the announcement data to encode 327 * @param maxPacketSize the maximum size of packets to produce 328 * @param constraints the constraints to apply when encoding the data, or 329 * <code>null</code> 330 * @return an iterator to use for encoding the data 331 * @throws NullPointerException if <code>announcement</code> is 332 * <code>null</code> 333 */ 334 public abstract EncodeIterator encodeMulticastAnnouncement( 335 MulticastAnnouncement announcement, 336 int maxPacketSize, 337 InvocationConstraints constraints); 338 339 /** 340 * Decodes the multicast announcement data contained in the given datagram 341 * in a manner that satisfies the specified constraints, returning a {@link 342 * MulticastAnnouncement} instance that contains the decoded data. 343 * <code>null</code> constraints are considered equivalent to empty 344 * constraints. All the specified constraints are checked before this 345 * method returns. 346 * 347 * @param packet the packet to decode 348 * @param constraints the constraints to apply when decoding the packet, or 349 * <code>null</code> 350 * @return the decoded multicast announcement data 351 * @throws IOException if an error occurs in interpreting the data 352 * @throws UnsupportedConstraintException if unable to satisfy the 353 * specified constraints 354 * @throws SecurityException if the given constraints cannot be satisfied 355 * due to insufficient caller permissions 356 * @throws NullPointerException if <code>packet</code> is <code>null</code> 357 */ 358 public abstract MulticastAnnouncement decodeMulticastAnnouncement( 359 DatagramPacket packet, 360 InvocationConstraints constraints) 361 throws IOException; 362 363 /** 364 * Decodes the multicast announcement data contained in the given datagram 365 * in a manner that satisfies the specified constraints, returning a {@link 366 * MulticastAnnouncement} instance that contains the decoded data, with 367 * constraint checking optionally delayed. <code>null</code> constraints 368 * are considered equivalent to empty constraints. 369 * <p>The <code>delayConstraintCheck</code> flag is used to control delayed 370 * constraint checking. Delayed constraint checking is useful for 371 * potentially delaying the expense of complete constraint checking, until 372 * other checks have been made on the returned 373 * <code>MulticastAnnouncement</code> for preliminary validation. 374 * Implementations may ignore the flag, in which case, the behavior is 375 * equivalent to that of {@link 376 * Discovery#decodeMulticastAnnouncement(DatagramPacket, 377 * InvocationConstraints) decodeMulticastAnnouncement}. 378 * <p>If <code>delayConstraintCheck</code> is <code>true</code>, the method 379 * behaves as follows:<ul> 380 * <li> Some of the specified constraints may not be checked before this 381 * method returns; the returned <code>MulticastAnnouncement</code>'s 382 * {@link MulticastAnnouncement#checkConstraints checkConstraints} 383 * method must be invoked to complete checking of all the constraints. 384 * <li> Constraints which must be checked before accessor methods of the 385 * returned <code>MulticastAnnouncement</code> can be invoked are always 386 * checked before this method returns.</ul> 387 * <p> If <code>delayConstraintCheck</code> is <code>false</code>, 388 * all the specified constraints are checked before this method returns. 389 * <p><code>Discovery</code> implements this method to simply invoke {@link 390 * Discovery#decodeMulticastAnnouncement(DatagramPacket, 391 * InvocationConstraints) decodeMulticastAnnouncement}, and thus checks 392 * all the specified constraints before returning. 393 * 394 * @param packet the packet to decode 395 * @param constraints the constraints to apply when decoding the packet, or 396 * <code>null</code> 397 * @param delayConstraintCheck flag to control delayed constraint checking 398 * @return the decoded multicast announcement data. 399 * @throws IOException if an error occurs in interpreting the data 400 * @throws UnsupportedConstraintException if unable to satisfy the 401 * specified constraints 402 * @throws SecurityException if the given constraints cannot be satisfied 403 * due to insufficient caller permissions. 404 * @throws NullPointerException if <code>packet</code> is <code>null</code> 405 * @since 2.1 406 */ 407 public MulticastAnnouncement decodeMulticastAnnouncement( 408 DatagramPacket packet, 409 InvocationConstraints constraints, 410 boolean delayConstraintCheck) 411 throws IOException 412 { 413 return decodeMulticastAnnouncement(packet, constraints); 414 } 415 416 /** 417 * Performs the client side of unicast discovery, obtaining the returned 418 * response data over the provided socket using the given default and 419 * codebase verifier class loaders and collection of object stream context 420 * objects in a manner that satisfies the specified constraints. 421 * <code>null</code> constraints are considered equivalent to empty 422 * constraints. 423 * 424 * @param socket the socket on which to perform unicast discovery 425 * @param constraints the constraints to apply to unicast discovery, or 426 * <code>null</code> 427 * @param defaultLoader the class loader value (possibly <code>null</code>) 428 * to be passed as the <code>defaultLoader</code> argument to 429 * <code>RMIClassLoader</code> methods when unmarshalling the registrar 430 * proxy 431 * @param verifierLoader the class loader value (possibly 432 * <code>null</code>) to pass to {@link 433 * net.jini.security.Security#verifyCodebaseIntegrity 434 * Security.verifyCodebaseIntegrity}, if codebase integrity verification is 435 * used when unmarshalling the registrar proxy 436 * @param context the collection of context information objects (possibly 437 * <code>null</code>) to use when unmarshalling the registrar proxy 438 * @return the received unicast response data 439 * @throws IOException if an error occurs in interpreting received data or 440 * in formatting data to send 441 * @throws UnsupportedConstraintException if unable to satisfy the 442 * specified constraints 443 * @throws SecurityException if the given constraints cannot be satisfied 444 * due to insufficient caller permissions 445 * @throws ClassNotFoundException if the class of the discovered registrar 446 * cannot be resolved 447 * @throws NullPointerException if <code>socket</code> is <code>null</code> 448 */ 449 public abstract UnicastResponse doUnicastDiscovery( 450 Socket socket, 451 InvocationConstraints constraints, 452 ClassLoader defaultLoader, 453 ClassLoader verifierLoader, 454 Collection context) 455 throws IOException, ClassNotFoundException; 456 457 /** 458 * Handles the server side of unicast discovery, transmitting the given 459 * response data over the provided socket using the given collection of 460 * object stream context objects in a manner that satisfies the specified 461 * constraints and client subject checker (if any). This method assumes 462 * that the protocol version number has already been consumed from the 463 * socket, but that no further processing of the connection has occurred. 464 * <code>null</code> constraints are considered equivalent to empty 465 * constraints. 466 * 467 * @param response the unicast response data to transmit 468 * @param socket the socket on which to handle unicast discovery 469 * @param constraints the constraints to apply to unicast discovery, or 470 * <code>null</code> 471 * @param checker the object to use to check the client subject, or 472 * <code>null</code> 473 * @param context the collection of context information objects to use when 474 * marshalling the registrar proxy 475 * @throws IOException if the protocol handshake fails, or if an error 476 * occurs in interpreting received data or in formatting data to send 477 * @throws UnsupportedConstraintException if unable to satisfy the 478 * specified constraints 479 * @throws SecurityException if the given constraints cannot be satisfied 480 * due to insufficient caller permissions, or if the client subject check 481 * fails 482 * @throws NullPointerException if <code>response</code>, 483 * <code>socket</code>, or <code>context</code> is <code>null</code> 484 */ 485 public abstract void handleUnicastDiscovery( 486 UnicastResponse response, 487 Socket socket, 488 InvocationConstraints constraints, 489 ClientSubjectChecker checker, 490 Collection context) 491 throws IOException; 492 }