xref: /illumos-gate/usr/src/lib/libslp/javalib/com/sun/slp/SunServerDATable.java (revision 8d483882aa3390058094b043f3d62187b5d1de03)
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) 2001 by Sun Microsystems, Inc.
26  * All rights reserved.
27  *
28  */
29 
30 //  SCCS Status:      %W%	%G%
31 //  SunServerDATable.java: Server DA Table for Sun's client/SA server SLP.
32 //  Author:           James Kempf
33 //  Created On:       Wed May 20 09:58:46 1998
34 //  Last Modified By: James Kempf
35 //  Last Modified On: Mon Mar  8 14:30:29 1999
36 //  Update Count:     79
37 //
38 
39 package com.sun.slp;
40 
41 import java.util.*;
42 import java.net.*;
43 import java.io.*;
44 
45 /**
46  * SunServerDATable is a subclass class that provides the
47  * implementation for DA storage on Solaris. As described in
48  * the header for SunDATable, DA information is stored in the server's
49  * SA table as the service type "directory-agent.sun"  with a
50  * attribute, scopes. The attribute contains a list of scopes supported
51  * by the DA. The service: URL of the registration contains the
52  * DA address as the host, followed by the list of scopes as an attribute
53  * in the URL part. An example is:
54  *
55  *   service:directory-agent.sun:// 199.200.200.5/scopes=eng, corp, freeb
56  *
57  * The scopes of the registration are the scopes provided as the Sun-specific
58  * system property "sun.net.slp.SAOnlyScopes". By convention, this is
59  * initialized to be the local machine name, but it may also include other
60  * names.
61  *
62  * @version %R%.%L% %D%
63  * @author James Kempf
64  */
65 
66 class SunServerDATable extends ServerDATable {
67 
68     // DA boot timestamp.
69 
70     static final private String TIMESTAMP_ID =
71 	"424242SUN-TABLE-TIMESTAMP424242";
72 
73     // Address. Makes deletion easier.
74 
75     static final private String ADDRESS_ID = "424242SUN-TABLE-ADDRESS424242";
76 
77     private ServiceTable serviceTable = null;  // SA table for regs.
78     private Vector saOnlyScopes = null;	       // Scopes for SA only.
79 
80     SunServerDATable() {
81 
82 	// Get the service table.
83 
84 	try {
85 
86 	    serviceTable = ServiceTable.getServiceTable();
87 
88 	} catch (ServiceLocationException ex) {
89 
90 	}
91 
92 	// Get the vector of SA scopes.
93 
94 	saOnlyScopes = conf.getSAOnlyScopes();
95 
96 	Assert.slpassert(saOnlyScopes.size() > 0,
97 		      "no_sa_scopes",
98 		      new Object[0]);
99 
100     }
101 
102     /**
103      * Record a new DA in the service table.
104      *
105      * @param URL The DAAdvert URL.
106      * @param scopes The scopes.
107      * @param version DA version number.
108      * @param spis SPIs this DA can support
109      * @return The boot timestamp in the previous registration. Used
110      *         to determine if registration is necessary. If an error occurs,
111      *	       the returned value is negative. If the DA is new, the return
112      *         value is the maximum long value. This will cause all
113      *         registrations to be forwarded, because it is larger than any
114      *         current time.
115      */
116 
117     public synchronized long
118 	recordNewDA(ServiceURL url,
119 		    Vector scopes,
120 		    long timestamp,
121 		    int version,
122 		    Vector attrs,
123 		    String spis) {
124 
125 	String addr = url.getHost();
126 	long formerTimestamp = -1L;
127 
128 	// We record all DAs regardless of whether we support them or not,
129 	//  because a UA client may be using the user selectable scoping
130 	//  model and therefore may want to see them.
131 
132 	Vector v = (Vector)scopes.clone();
133 
134 	// Add the Sun attributes.
135 
136 	ServiceLocationAttribute attr =
137 	    new ServiceLocationAttribute(SunDATable.SCOPES_ID, scopes);
138 	attrs.addElement(attr);
139 
140 	Vector vals = new Vector();
141 	vals.addElement(Long.toString(timestamp));
142 	attr =
143 	    new ServiceLocationAttribute(SunServerDATable.TIMESTAMP_ID, vals);
144 	attrs.addElement(attr);
145 
146 	vals = new Vector();
147 	vals.addElement(new Integer(version));
148 	attr = new ServiceLocationAttribute(SunDATable.VERSION_ID, vals);
149 	attrs.addElement(attr);
150 
151 	vals = new Vector();
152 	vals.addElement(url.getHost());
153 	attr = new ServiceLocationAttribute(SunServerDATable.ADDRESS_ID, vals);
154 	attrs.addElement(attr);
155 
156 	// Form the URL for the DA.
157 
158 	ServiceURL adURL = formServiceTableDAURL(url, attrs);
159 
160 	// Reach *around* the service table for registration, because
161 	//  we don't need a message. The service table abstraction
162 	//  is basically for decoding message objects, and we already
163 	//  have things in the internal form needed by the service store.
164 
165 	ServiceStore store = serviceTable.store;
166 
167 	try {
168 
169 	    // First, get the boot time stamp if there.
170 
171 	    Vector tags = new Vector();
172 	    tags.addElement(SunServerDATable.TIMESTAMP_ID);
173 
174 	    Hashtable attrRec =
175 		store.findAttributes(adURL,
176 				     saOnlyScopes,
177 				     tags,
178 				     Defaults.locale);
179 
180 	    Vector formerAttrs =
181 		(Vector)attrRec.get(ServiceStore.FA_ATTRIBUTES);
182 
183 	    // If there, then get the old timestamp.
184 
185 	    if (formerAttrs != null && !(formerAttrs.size() <= 0)) {
186 
187 		// Get the timestamp into a long.
188 
189 		attr = (ServiceLocationAttribute)formerAttrs.elementAt(0);
190 		vals = attr.getValues();
191 		String stamp = (String)vals.elementAt(0);
192 
193 		try {
194 
195 		    formerTimestamp = Long.parseLong(stamp.trim());
196 
197 		} catch (NumberFormatException ex) {
198 
199 		    Assert.slpassert(false,
200 				  "ssdat_number_format",
201 				  new Object[0]);
202 
203 		}
204 	    }
205 
206 	    // Now register the URL.
207 
208 	    store.register(adURL,
209 			   attrs,
210 			   saOnlyScopes,
211 			   Defaults.locale,
212 			   null,
213 			   null);
214 
215 	    // Keep track of this DAs supported SPIs
216 	    LinkedList spiList =
217 		AuthBlock.commaSeparatedListToLinkedList(spis);
218 
219 	    // convert addr to an InetAddress for hashing
220 	    InetAddress inetAddr = null;
221 	    try {
222 		inetAddr = InetAddress.getByName(addr);
223 	    } catch (UnknownHostException e) {}
224 
225 	    // If we didn't get the InetAddress, this DA will never be used
226 	    // anyway
227 	    if (addr != null) {
228 		daSPIsHash.put(inetAddr, spiList);
229 	    }
230 
231 	} catch (ServiceLocationException ex) {
232 	    conf.writeLog("ssdat_register_error",
233 			  new Object[] {
234 		ex.getMessage(),
235 		    adURL,
236 		    saOnlyScopes});
237 	}
238 
239 	return formerTimestamp;
240     }
241 
242     /**
243      * Remove a DA. The Sun-specific convention is used to deregister
244      * the URL.
245      *
246      * @param address The host address of the DA, from its service URL.
247      * @param scopes The scopes.
248      * @return True if removed, false if not.
249      */
250 
251     public synchronized boolean removeDA(InetAddress address, Vector scopes) {
252 
253 	// Find URLs corresponding to this address.
254 
255 	String query = "(" + ADDRESS_ID + "=" + address.getHostAddress() + ")";
256 
257 	// Reach *around* the service table for dregistration, because
258 	//  we don't need a message. The service table abstraction
259 	//  is basically for decoding message objects, and we already
260 	//  have things in the internal form needed by the service store.
261 
262 	ServiceStore store = serviceTable.store;
263 
264 	try {
265 
266 	    Hashtable das = returnMatchingDAs(query);
267 
268 	    Enumeration daURLs = das.keys();
269 
270 	    while (daURLs.hasMoreElements()) {
271 		ServiceURL adURL = (ServiceURL)daURLs.nextElement();
272 		store.deregister(adURL, saOnlyScopes, null);
273 
274 	    }
275 
276 	} catch (ServiceLocationException ex) {
277 	    conf.writeLog("ssdat_deregister_error",
278 			  new Object[] {
279 		ex.getMessage(),
280 		    address,
281 		    saOnlyScopes});
282 
283 	    return false;
284 	}
285 
286 	return true;
287 
288     }
289 
290     /**
291      * Return a hashtable in ServiceTable.findServices() format (e.g.
292      * URL's as keys, scopes as values) for DAs matching the query.
293      *
294      * @param query Query for DA attributes.
295      */
296 
297     public synchronized Hashtable returnMatchingDAs(String query)
298 	throws ServiceLocationException {
299 	ServiceStore store = ServiceTable.getServiceTable().store;
300 
301 	// Get DA records matching the query.
302 
303 	Vector saOnlyScopes = conf.getSAOnlyScopes();
304 
305 	Hashtable returns =
306 	    store.findServices(Defaults.SUN_DA_SERVICE_TYPE.toString(),
307 			       saOnlyScopes,
308 			       query,
309 			       Defaults.locale);
310 
311 	// Return the hashtable of services v.s. scopes.
312 
313 	return (Hashtable)returns.get(ServiceStore.FS_SERVICES);
314     }
315 
316     /**
317      * Return a hashtable of DA equivalence classes and multicast
318      * scopes. Multicast scopes are stored in the special hashtable
319      * key MULTICAST_KEY. Unicast DA equivalence classes are stored
320      * under the key UNICAST_KEY. This implementation goes directly
321      * to the service table in the SA server for the DA addresses.
322      *
323      * @param scopes Scope list for DAs needed.
324      * @return Hashtable with DA addresses as keys and scopes to contact
325      *         them with as values. Any scopes not associated with a
326      *         DA come back stored under the key MULTICAST_KEY.
327      *         Unicast DA equivalence classes are stored
328      * 	     under the key UNICAST_KEY.
329      */
330 
331     public synchronized Hashtable findDAScopes(Vector scopes)
332 	throws ServiceLocationException {
333 
334 	// Formulate a query for the DAs.
335 
336 	int i, n = scopes.size();
337 	StringBuffer buf = new StringBuffer();
338 
339 	for (i = 0; i < n; i++) {
340 	    buf.append("(");
341 	    buf.append(SunDATable.SCOPES_ID);
342 	    buf.append("=");
343 	    buf.append((String)scopes.elementAt(i));
344 	    buf.append(")");
345 	}
346 
347 	// Add logical disjunction if more than one element.
348 
349 	if (i > 1) {
350 	    buf.insert(0, "(|");
351 	    buf.append(")");
352 
353 	}
354 
355 	// Add version number.
356 
357 	if (i > 0) {
358 	    buf.insert(0, "(&");
359 
360 	}
361 
362 	buf.append("(");
363 	buf.append(SunDATable.VERSION_ID);
364 	buf.append("=");
365 	buf.append((new Integer(Defaults.version)).toString());
366 	buf.append(")");
367 
368 	// Add closing paren if there were any scopes.
369 
370 	if (i > 0) {
371 	    buf.append(")");
372 
373 	}
374 
375 	ServiceStore store = serviceTable.store;
376 
377 	Hashtable returns =
378 	    store.findServices(Defaults.SUN_DA_SERVICE_TYPE.toString(),
379 			       saOnlyScopes,
380 			       buf.toString(),
381 			       Defaults.locale);
382 
383 	Hashtable retRec = (Hashtable)returns.get(ServiceStore.FS_SERVICES);
384 
385 	// Convert to a vector. Keys are the service: URLs.
386 
387 	Enumeration en = retRec.keys();
388 	Vector ret = new Vector();
389 	Vector multiScopes = (Vector)scopes.clone();
390 	Vector attrTags = new Vector();
391 
392 	attrTags.addElement(SunDATable.SCOPES_ID);
393 
394 	while (en.hasMoreElements()) {
395 	    ServiceURL url = (ServiceURL)en.nextElement();
396 	    Vector urlScopes = (Vector)retRec.get(url);
397 
398 	    // Get the scope attributes for this URL.
399 
400 	    Hashtable attrRec =
401 		store.findAttributes(url,
402 				     urlScopes,
403 				     attrTags,
404 				     Defaults.locale);
405 
406 	    Vector retAttrs = (Vector)attrRec.get(ServiceStore.FA_ATTRIBUTES);
407 	    String host = url.getHost();
408 	    Vector retScopes = null;
409 	    n = retAttrs.size();
410 
411 	    for (i = 0; i < n; i++) {
412 		ServiceLocationAttribute attr =
413 		    (ServiceLocationAttribute)retAttrs.elementAt(i);
414 
415 		// Distinguish based on type. We assume the attributes are
416 		// prescreened when the URL was formed to make sure they're OK
417 
418 		String id = attr.getId();
419 		Vector vals = attr.getValues();
420 
421 		if (id.equals(SunDATable.SCOPES_ID)) {
422 		    retScopes = vals;
423 
424 		}
425 	    }
426 
427 	    // Add to equivalence class.
428 
429 	    DATable.addToEquivClass(host, retScopes, ret);
430 
431 	    // Filter scopes for any that might be multicast.
432 
433 	    DATable.filterScopes(multiScopes, retScopes, false);
434 
435 	}
436 
437 	// Format the return.
438 
439 	retRec.clear();
440 
441 	if (multiScopes.size() > 0) {
442 	    retRec.put(DATable.MULTICAST_KEY, multiScopes);
443 
444 	}
445 
446 	if (ret.size() > 0) {
447 	    retRec.put(DATable.UNICAST_KEY, ret);
448 
449 	}
450 
451 	return retRec;
452     }
453 
454     // Form a URL for the service table, from the DA URL and attributes.
455     //  Attributes and scope have been prechecked for correctness.
456 
457     private ServiceURL formServiceTableDAURL(ServiceURL url, Vector attrs) {
458 
459 	// Form up the URL part.
460 
461 	StringBuffer buf = new StringBuffer();
462 
463 	int i, n = attrs.size();
464 
465 	for (i = 0; i < n; i++) {
466 	    ServiceLocationAttribute attr =
467 		(ServiceLocationAttribute)attrs.elementAt(i);
468 
469 	    // If this is a URL attribute, then externalize and
470 	    //  put into URL.
471 
472 	    String id = attr.getId();
473 
474 	    if (id.equals(SunDATable.SCOPES_ID)) {
475 		String rep = "";
476 
477 		try {
478 		    rep = attr.externalize();
479 
480 		} catch (ServiceLocationException ex) {
481 		    conf.writeLog("ssdat_inter_attr_err",
482 				  new Object[] {attr, ex.getMessage()});
483 		    continue;
484 
485 		}
486 
487 		// Add semi if something already there.
488 
489 		if (buf.length() > 0) {
490 		    buf.append(";");
491 
492 		}
493 
494 		// Remove parens before inserting.
495 
496 		buf.append(rep.substring(1, rep.length()-1));
497 
498 	    }
499 	}
500 
501 	// Create the URL.
502 
503 	ServiceURL daURL =
504 	    new ServiceURL(Defaults.SUN_DA_SERVICE_TYPE+
505 			   "://"+
506 			   url.getHost()+
507 			   "/"+
508 			   buf.toString(),
509 			   url.getLifetime());
510 	return daURL;
511 
512     }
513 }
514