xref: /illumos-gate/usr/src/lib/libslp/javalib/com/sun/slp/UARequester.java (revision efd4c9b63ad77503c101fc6c2ed8ba96c9d52964)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 1999 by Sun Microsystems, Inc.
23  * All rights reserved.
24  *
25  */
26 
27 //  UARequester.java: Requester operations for UA.
28 //  Author:           James Kempf
29 //  Created On:       Thu Jan  8 15:17:35 1998
30 //  Last Modified By: James Kempf
31 //  Last Modified On: Mon Feb 22 13:47:06 1999
32 //  Update Count:     78
33 //
34 
35 package com.sun.slp;
36 
37 import java.util.*;
38 
39 /**
40  * The URequester class implements the Locator interface.
41  * It handles the request for the API.  If any of the parameters
42  * are missing, they will be supplied with a default value if
43  * possible.  If a cached value may be supplied, it will be.
44  * If no DA is present, and convergence is used to gather
45  * results, these will be merged into one result.
46  *
47  * @author Erik Guttman, James Kempf
48  */
49 
50 
51 class UARequester extends Object implements Locator {
52 
53     private static SLPConfig config = null;
54     private static DATable dat = null;
55 
56     private Locale locale;
57 
58     UARequester(Locale nlocale) {
59 
60 	Assert.nonNullParameter(nlocale, "locale");
61 
62 	if (config == null) {
63 	    config = SLPConfig.getSLPConfig();
64 	}
65 
66 	if (dat == null) {
67 	    dat = DATable.getDATable();
68 	}
69 
70 	locale = nlocale;
71     }
72 
73     /**
74      * Return the Locator's locale object. All requests are made in
75      * this locale.
76      *
77      * @return The Locale object.
78      */
79 
80     public Locale getLocale() {
81 	return locale;
82 
83     }
84 
85     /**
86      * Return an enumeration of known service types for this scope and naming
87      * authority.  Unless a proprietary or experimental service is being
88      * discovered, the namingAuthority parameter should be the empty
89      * string, "".
90      *
91      * @param NA	The naming authority, "" for default,
92      *           '*' for any naming authority.
93      * @param scopes	The SLP scopes of the types.
94      * @return ServiceLocationEnumeration of ServiceType objects for
95      *	      the service type names.
96      * @exception IllegalArgumentException If any of the parameters are
97      *					  null or syntactically incorrect.
98      * @exception ServiceLocationException An exception is thrown if the
99      *					  operation fails.
100      */
101 
102     public synchronized ServiceLocationEnumeration
103 	findServiceTypes(String NA, Vector scopes)
104 	throws ServiceLocationException {
105 
106 	Assert.nonNullParameter(NA, " NA");
107 	Assert.nonNullParameter(scopes, "scopes");
108 
109 	// Formulate and send off messages.
110 
111 	Vector msgs = createMessages(SrvLocHeader.SrvTypeRqst,
112 				     NA,
113 				     null,
114 				     null,
115 				     scopes);
116 
117 	// Collate results.
118 
119 	Vector ret = new Vector();
120 	int i, n = msgs.size();
121 	int max = config.getMaximumResults();
122 
123 	for (i = 0; i < n; i++) {
124 	    CSrvTypeMsg msg = (CSrvTypeMsg)msgs.elementAt(i);
125 
126 	    // Check for errors.
127 
128 	    checkForError(msg, msgs);
129 
130 	    Vector serviceTypes = msg.serviceTypes;
131 
132 	    addUnique(serviceTypes, ret, max);
133 
134 	}
135 
136 	// Return.
137 
138 	return new ServiceLocationEnumerator(ret);
139     }
140 
141     /**
142      * Return an enumeration of ServiceURL objects for services matching
143      * the query. The services are returned from the locale of the
144      * locator.
145      *
146      * @param type	The type of the service (e.g. printer, etc.).
147      * @param scopes	The SLP scopes of the service types.
148      * @param query		A string with the SLP query.
149      * @return ServiceLocationEnumeration of ServiceURL objects for
150      *	      services matching the
151      *         attributes.
152      * @exception ServiceLocationException An exception is returned if the
153      *					  operation fails.
154      * @see ServiceURL
155      */
156 
157     public synchronized ServiceLocationEnumeration
158 	findServices(ServiceType type, Vector scopes, String query)
159 	throws ServiceLocationException {
160 
161 	Assert.nonNullParameter(type, "type");
162 	Assert.nonNullParameter(scopes, "scopes");
163 	Assert.nonNullParameter(query, "query");
164 
165 	// Formulate and send off messages.
166 
167 	Vector msgs = createMessages(SrvLocHeader.SrvReq,
168 				     type,
169 				     query,
170 				     type,
171 				     scopes);
172 
173 	// Collate results.
174 
175 	Vector ret = new Vector();
176 	int i, n = msgs.size();
177 	int max = config.getMaximumResults();
178 
179 	for (i = 0; i < n; i++) {
180 	    SrvLocMsg msg = (SrvLocMsg)msgs.elementAt(i);
181 
182 	    // Check for errors.
183 
184 	    checkForError(msg, msgs);
185 
186 	    // Be sure to account for DAAdverts and SAAdverts.
187 
188 	    Vector serviceURLs = null;
189 
190 	    if (msg instanceof CSrvMsg) {
191 		serviceURLs = ((CSrvMsg)msg).serviceURLs;
192 
193 	    } else if (msg instanceof CSAAdvert) {
194 		serviceURLs = new Vector();
195 		serviceURLs.addElement(((CSAAdvert)msg).URL);
196 
197 	    } else if (msg instanceof CDAAdvert) {
198 		serviceURLs = new Vector();
199 		serviceURLs.addElement(((CDAAdvert)msg).URL);
200 
201 	    }
202 
203 	    addUnique(serviceURLs, ret, max);
204 
205 	}
206 
207 	// Return.
208 
209 	return new ServiceLocationEnumerator(ret);
210     }
211 
212     /**
213      * Return the attributes for the service URL, using the locale
214      * of the locator.
215      *
216      * @param URL	The service URL.
217      * @param scopes	The SLP scopes of the service.
218      * @param attributeIds A vector of strings identifying the desired
219      *			  attributes. A null value means return all
220      *			  the attributes.  <b>Partial id strings</b> may
221      *                     begin with '*' to match all ids which end with
222      *                     the given suffix, or end with '*' to match all
223      *                     ids which begin with a given prefix, or begin
224      *                     and end with '*' to do substring matching for
225      *                     ids containing the given partial id.
226      * @return ServiceLocationEnumeration of ServiceLocationAttribute
227      *         objects matching the ids.
228      * @exception ServiceLocationException An exception is returned if the
229      *					  operation fails.
230      * @exception IllegalArgumentException If any of the parameters are
231      *					  null or syntactically incorrect.
232      * @see ServiceLocationAttribute
233      *
234      */
235 
236     public synchronized ServiceLocationEnumeration
237 	findAttributes(ServiceURL URL, Vector scopes, Vector attributeIds)
238 	throws ServiceLocationException {
239 
240 	Assert.nonNullParameter(URL, "URL");
241 	Assert.nonNullParameter(scopes, "scopes");
242 	Assert.nonNullParameter(attributeIds, "attributeIds");
243 
244 	Vector msgs = createMessages(SrvLocHeader.AttrRqst,
245 				     URL,
246 				     attributeIds,
247 				     URL.getServiceType(),
248 				     scopes);
249 
250 	// Check results.
251 
252 	Vector ret = new Vector();
253 	int i, n = msgs.size();
254 	int max = config.getMaximumResults();
255 
256 	// We only take the first message that came back and is OK.
257 
258 	for (i = 0; i < n; i++) {
259 	    SrvLocMsg msg = (SrvLocMsg)msgs.elementAt(i);
260 
261 	    // Check for errors.
262 
263 	    checkForError(msg, msgs);
264 
265 	    // Select out attribute list.
266 
267 	    if (msg instanceof CAttrMsg) {
268 		ret = ((CAttrMsg)msg).attrList;
269 
270 	    } else if (msg instanceof CSAAdvert) {
271 
272 		// Need to check that URL matches.
273 
274 		CSAAdvert smsg = (CSAAdvert)msg;
275 
276 		if (!URL.equals(smsg.URL)) {
277 		    continue;
278 
279 		}
280 
281 		ret = smsg.attrs;
282 
283 	    } else if (msg instanceof CDAAdvert) {
284 
285 		// Need to check that URL matches.
286 
287 		CDAAdvert smsg = (CDAAdvert)msg;
288 
289 		if (!URL.equals(smsg.URL)) {
290 		    continue;
291 
292 		}
293 
294 		ret = smsg.attrs;
295 	    }
296 
297 	    // Truncate, if return is larger than maximum.
298 
299 	    if (ret.size() > max) {
300 		ret.setSize(max);
301 
302 	    }
303 
304 	    // Break out, we only need one.
305 
306 	    break;
307 
308 	}
309 
310 	// Return.
311 
312 	return new ServiceLocationEnumerator(ret);
313     }
314 
315     /**
316      * Return all attributes for all service URL's having this
317      * service type in the locale of the Locator.
318      *
319      * @param type The service type.
320      * @param scopes	The SLP scopes of the service type.
321      * @param attributeIds A vector of strings identifying the desired
322      *			  attributes. A null value means return all
323      *			  the attributes.  <b>Partial id strings</b> may
324      *                     begin with '*' to match all ids which end with
325      *                     the given suffix, or end with '*' to match all
326      *                     ids which begin with a given prefix, or begin
327      *                     and end with '*' to do substring matching for
328      *                     ids containing the given partial id.
329      * @return ServiceLocationEnumeration of ServiceLocationAttribute
330      *         objects matching the ids.
331      * @exception ServiceLocationException An exception is returned if the
332      *					  operation fails.
333      * @exception IllegalArgumentException If any of the parameters are
334      *					  null or syntactically incorrect.
335      * @see ServiceLocationAttribute
336      *
337      */
338 
339     public synchronized ServiceLocationEnumeration
340 	findAttributes(ServiceType type, Vector scopes, Vector attributeIds)
341 	throws ServiceLocationException {
342 
343 	Assert.nonNullParameter(type, "URL");
344 	Assert.nonNullParameter(scopes, "scopes");
345 	Assert.nonNullParameter(attributeIds, "attributeIds");
346 
347 	// Formulate and send off messages.
348 
349 	Vector msgs = createMessages(SrvLocHeader.AttrRqst,
350 				     type,
351 				     attributeIds,
352 				     type,
353 				     scopes);
354 	// Collate results.
355 
356 	Vector ret = new Vector();
357 	int i, n = msgs.size();
358 	int max = config.getMaximumResults();
359 	Hashtable ht = new Hashtable();
360 
361 	for (i = 0; i < n && ret.size() < max; i++) {
362 	    SrvLocMsg msg = (SrvLocMsg)msgs.elementAt(i);
363 
364 	    // Check for errors.
365 
366 	    checkForError(msg, msgs);
367 
368 	    Vector attrList = null;
369 
370 	    // Get the instance variable.
371 
372 	    if (msg instanceof CAttrMsg) {
373 		attrList = ((CAttrMsg)msg).attrList;
374 
375 	    } else if (msg instanceof CSAAdvert) {
376 		attrList = ((CSAAdvert)msg).attrs;
377 
378 	    } else if (msg instanceof CDAAdvert) {
379 		attrList = ((CDAAdvert)msg).attrs;
380 
381 	    }
382 
383 	    // Merge any duplicates.
384 
385 	    int j, m = attrList.size();
386 
387 	    for (j = 0; j < m; j++) {
388 		ServiceLocationAttribute attr =
389 		    (ServiceLocationAttribute)attrList.elementAt(j);
390 
391 		ServiceLocationAttribute.mergeDuplicateAttributes(attr,
392 								  ht,
393 								  ret,
394 								  true);
395 
396 		if (ret.size() >= max) {
397 		    break;
398 
399 		}
400 	    }
401 	}
402 
403 	// Return.
404 
405 	return new ServiceLocationEnumerator(ret);
406     }
407 
408     // Execute the message request, returning messages.
409 
410     private Vector
411 	createMessages(int msgType,
412 		       Object t1,
413 		       Object t2,
414 		       ServiceType type,
415 		       Vector scopes)
416 	throws ServiceLocationException {
417 
418 	// Validate, lower case scopes.
419 
420 	DATable.validateScopes(scopes, locale);
421 
422 	SrvLocMsg multiMsg = null;
423 	SrvLocMsg uniMsg = null;
424 	Vector daAddresses = null;
425 	Vector multiCastScopes = null;
426 
427 	// Get the hashtable of unicast DA addresses and multicast scopes.
428 
429 	Hashtable daRecords = dat.findDAScopes(scopes);
430 
431 	// Get multicast scopes and DA addresses.
432 
433 	multiCastScopes =
434 	    (Vector)daRecords.get(DATable.MULTICAST_KEY);
435 
436 	daAddresses =
437 	    (Vector)daRecords.get(DATable.UNICAST_KEY);
438 
439 	// Special case for service request and attribute request
440 	//  if the user is looking for a special SLP type.
441 
442 	if (((msgType == SrvLocHeader.SrvReq) ||
443 	    (msgType == SrvLocHeader.AttrRqst)) &&
444 	    (type.equals(Defaults.DA_SERVICE_TYPE) ||
445 	    type.equals(Defaults.SA_SERVICE_TYPE))) {
446 
447 	    multiCastScopes = scopes;
448 	    daAddresses = null;
449 
450 	    // Get query. If an attribute request, then the user
451 	    //  needs to sort out the attributes.
452 
453 	    String query = "";
454 
455 	    if (msgType == SrvLocHeader.SrvReq) {
456 		query = (String)t2;
457 
458 	    }
459 
460 	    multiMsg = new CSrvMsg(locale, type, multiCastScopes, query);
461 
462 	} else {
463 
464 	    // Handle a regular message.
465 
466 	    // Multicast scopes are all scopes not supported by any DA.
467 
468 	    if (multiCastScopes != null) {
469 
470 		switch (msgType) {
471 
472 		case SrvLocHeader.SrvTypeRqst:
473 		    multiMsg =
474 			new CSrvTypeMsg(locale, (String)t1, multiCastScopes);
475 		    break;
476 
477 		case SrvLocHeader.SrvReq:
478 		    multiMsg =
479 			new CSrvMsg(locale, type, multiCastScopes, (String)t2);
480 		    break;
481 
482 		case SrvLocHeader.AttrRqst:
483 
484 		    if (t1 instanceof ServiceURL) {
485 			multiMsg =
486 			    new CAttrMsg(locale,
487 					 (ServiceURL)t1,
488 					 multiCastScopes,
489 					 (Vector)t2);
490 
491 		    } else {
492 			multiMsg =
493 			    new CAttrMsg(locale,
494 					 type,
495 					 multiCastScopes,
496 					 (Vector)t2);
497 
498 		    }
499 		}
500 	    }
501 
502 	    // Unicast only requires a single message because the DAs will
503 	    //  ignore any scopes they do not support, just as long as
504 	    //  they support one of them.
505 
506 	    if (daAddresses != null) {
507 		switch (msgType) {
508 
509 		case SrvLocHeader.SrvTypeRqst:
510 		    uniMsg =
511 			new CSrvTypeMsg(locale, (String)t1, scopes);
512 		    break;
513 
514 		case SrvLocHeader.SrvReq:
515 		    uniMsg =
516 			new CSrvMsg(locale, type, scopes, (String)t2);
517 		    break;
518 
519 		case SrvLocHeader.AttrRqst:
520 
521 		    if (t1 instanceof ServiceURL) {
522 			uniMsg =
523 			    new CAttrMsg(locale,
524 					 (ServiceURL)t1,
525 					 scopes,
526 					 (Vector)t2);
527 
528 		    } else {
529 			uniMsg =
530 			    new CAttrMsg(locale,
531 					 type,
532 					 scopes,
533 					 (Vector)t2);
534 
535 		    }
536 
537 		}
538 	    }
539 	}
540 
541 	// Send off messages, return results.
542 
543 	return Transact.transactUA(daAddresses,
544 				   uniMsg,
545 				   multiMsg,
546 				   config.getMulticastAddress());
547     }
548 
549     // Check message for error code.
550 
551     private static void
552 	checkForError(SrvLocMsg msg, Vector v)
553 	throws ServiceLocationException {
554 	int err = msg.getErrorCode();
555 
556 	if (err != ServiceLocationException.OK) {
557 	    if (v.size() == 1) {
558 		config.writeLog("single_exception",
559 				new Object[] {
560 		    new Integer(err)});
561 		throw
562 		    new ServiceLocationException((short)err,
563 						 "remote_error",
564 						 new Object[] {});
565 	    } else {
566 		config.writeLog("multiple_exception",
567 				new Object[] {
568 		    new Integer(err)});
569 	    }
570 	}
571     }
572 
573     // Process the incoming vector, adding any unique returns.
574 
575     private static void addUnique(Vector incoming, Vector returns, int max) {
576 
577 	int i, n = incoming.size();
578 
579 	for (i = 0; i < n; i++) {
580 	    Object o = incoming.elementAt(i);
581 
582 	    if (!returns.contains(o) && returns.size() < max) {
583 		returns.addElement(o);
584 
585 	    }
586 	}
587     }
588 
589 }
590