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 }