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