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