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 SunServerDATable()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 recordNewDA(ServiceURL url, Vector scopes, long timestamp, int version, Vector attrs, String spis)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 removeDA(InetAddress address, Vector scopes)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 returnMatchingDAs(String query)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 findDAScopes(Vector scopes)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 formServiceTableDAURL(ServiceURL url, Vector attrs)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