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