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