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 2001,2003 Sun Microsystems, Inc. All rights reserved. 26 * Use is subject to license terms. 27 * 28 */ 29 30 // SCCS Status: %W% %G% 31 // DATable.java: Interface for DATables. 32 // Author: James Kempf 33 // Created On: Mon May 11 13:46:02 1998 34 // Last Modified By: James Kempf 35 // Last Modified On: Mon Feb 22 15:47:37 1999 36 // Update Count: 53 37 // 38 39 40 package com.sun.slp; 41 42 /** 43 * DATable is an abstract class that provides the interface for DA 44 * and scope discovery. A variety of implementations are possible. 45 * The getDATable() method creates the right one from a subclass. 46 * 47 * @version %R%.%L% %D% 48 * @author James Kempf 49 */ 50 51 import java.util.*; 52 import java.net.*; 53 54 abstract class DATable extends Object { 55 56 protected static DATable daTable; 57 protected static SLPConfig conf; 58 59 // System property naming the DATable implementation class to use. 60 61 final static String DA_TABLE_CLASS_PROP = "sun.net.slp.DATableClass"; 62 63 // SA only scopes property. 64 65 final static String SA_ONLY_SCOPES_PROP = "sun.net.slp.SAOnlyScopes"; 66 67 // Hashtable key for multicast scopes. 68 69 final static String MULTICAST_KEY = "&&**^^MULTICASTxxxKEY^^**&&"; 70 71 // Hashtable key for DA equivalence classes. 72 73 final static String UNICAST_KEY = "&&**^^UNICASTxxxKEY^^**&&"; 74 75 /** 76 * A record for all DAs supporting exactly the same set of scopes. 77 * 78 * @version %R%.%L% %D% 79 * @author James Kempf 80 */ 81 82 83 public static class DARecord extends Object { 84 85 // The scopes supported. 86 87 Vector scopes = null; // String scope names 88 89 Vector daAddresses = new Vector(); // InetAddress DA addresses 90 91 } 92 93 /** 94 * Return a hashtable containing two entries: 95 * 96 * MULTICAST_KEY - Vector of scopes from the incoming vector that are not 97 * supported by any known DA. 98 * 99 * UNICAST_KEY - Vector of DATable.DARecord objects containing 100 * equivalence classes of DAs that all support the same set of scopes. 101 * Only DAs supporting one or more scopes in the incoming vector 102 * are returned. 103 * 104 * Note that the equivalence classes don't necessarily mean that the 105 * set of scopes are mutually exclusive. For example, if DA1 supports 106 * scopes A, B, and C; and DA2 supports scopes C and D, then they 107 * are in separate equivalence classes even though they both support 108 * C. But if DA2 supports A, B, and C; then it is in the same equivalence 109 * class. 110 * 111 * @param scopes The scopes for which DAs are required. 112 * @return A Hashtable with the multicast scopes and DAAddresses. 113 */ 114 115 abstract Hashtable findDAScopes(Vector scopes) 116 throws ServiceLocationException; 117 118 /** 119 * Remove a DA by address. 120 * 121 * @param address The host address of the DA. 122 * @param scopes The scopes. 123 * @return True if removed, false if not. 124 */ 125 126 abstract boolean removeDA(InetAddress address, Vector scopes); 127 128 /** 129 * Return a vector of scopes that the SA or UA client should use. 130 * Note that if no DAs are around, SA adverts must be used to 131 * find SAs. We must sort through the returned DAs and apply 132 * the scope prioritization algorithm to them. 133 * 134 * @return Vector of scopes for the SA or UA client to use. 135 */ 136 137 synchronized Vector findScopes() throws ServiceLocationException { 138 139 // First, get the DA addresses v.s. scopes table from the DAtable. 140 // This will also include DA addresses from the configuration file, 141 // if any. We don't filter on any scopes, since we want all of 142 // them. We are only interested in v2 scopes here. 143 144 Vector scopes = new Vector(); 145 Hashtable daRec = daTable.findDAScopes(scopes); 146 Vector daEquivClasses = (Vector)daRec.get(UNICAST_KEY); 147 148 if (daEquivClasses != null) { 149 150 // Go through the equivalence classes and pull out scopes. 151 152 int i, n = daEquivClasses.size(); 153 154 for (i = 0; i < n; i++) { 155 DARecord rec = (DARecord)daEquivClasses.elementAt(i); 156 Vector v = rec.scopes; 157 158 int j, m = v.size(); 159 160 for (j = 0; j < m; j++) { 161 Object s = v.elementAt(j); 162 163 // Unicast scopes take precedence over multicast scopes, 164 // so insert them at the beginning of the vector. 165 166 if (!scopes.contains(s)) { 167 scopes.addElement(s); 168 169 } 170 } 171 } 172 } 173 174 return scopes; 175 } 176 177 /** 178 * Get the right DA table implementation. The property 179 * sun.net.slp.DATableClass determines the class. 180 * 181 * @return The DATable object for this process' SLP requests. 182 */ 183 184 185 static DATable getDATable() { 186 187 // Return it right up front if we have it. 188 189 if (daTable != null) { 190 return daTable; 191 192 } 193 194 conf = SLPConfig.getSLPConfig(); 195 196 // Link and instantiate it. 197 198 daTable = linkAndInstantiateFromProp(); 199 200 return daTable; 201 202 } 203 204 // Link and instantiate the class in the property. 205 206 static protected DATable linkAndInstantiateFromProp() { 207 208 // Get the property. 209 210 String className = System.getProperty(DA_TABLE_CLASS_PROP); 211 212 if (className == null) { 213 Assert.slpassert(false, 214 "no_da_table", 215 new Object[] {DA_TABLE_CLASS_PROP}); 216 } 217 218 Class tclass = null; 219 220 // Link the class and instantiate the object. 221 222 try { 223 224 tclass = Class.forName(className); 225 daTable = (DATable)tclass.newInstance(); 226 return daTable; 227 228 } catch (ClassNotFoundException ex) { 229 230 Assert.slpassert(false, 231 "no_da_table_class", 232 new Object[] {className}); 233 234 } catch (InstantiationException ex) { 235 236 Assert.slpassert(false, 237 "instantiation_exception", 238 new Object[] {className}); 239 240 } catch (IllegalAccessException ex) { 241 242 Assert.slpassert(false, 243 "access_exception", 244 new Object[] {className}); 245 246 } 247 248 // We won't reach this point, since the assertions will capture 249 // any errors and kill the program. 250 251 return null; 252 } 253 254 // 255 // Utility functions for DA filtering and handling scopes. 256 // 257 258 // Filter scopes, removing any not on the filter list if inVector is 259 // false and removing any in the filter list if inVector is true. 260 261 public static void 262 filterScopes(Vector scopes, Vector filter, boolean inVector) { 263 264 int i = 0; 265 266 // Null or empty filter vector means that all should be accepted. 267 268 if (filter != null && !(filter.size() <= 0)) { 269 270 while (i < scopes.size()) { 271 String scope = (String)scopes.elementAt(i); 272 273 if ((!inVector && !filter.contains(scope)) || 274 (inVector && filter.contains(scope))) { 275 scopes.removeElementAt(i); 276 277 } else { 278 i++; 279 280 } 281 } 282 } 283 } 284 285 // Add a new address to the equivalence class. 286 287 static boolean addToEquivClass(String daaddr, Vector scopes, Vector ret) { 288 289 // Create the InetAddress object. 290 291 InetAddress addr = null; 292 293 try { 294 295 addr = InetAddress.getByName(daaddr); 296 297 } catch (UnknownHostException ex) { 298 299 if (conf.traceAll()) { 300 conf.writeLog("unknown_da_address", 301 new Object[] {daaddr}); 302 303 } 304 305 return false; 306 } 307 308 // Go through the existing vector. 309 310 int i, n = ret.size(); 311 boolean equivalent = false; 312 DARecord rec = null; 313 314 outer: for (i = 0; i < n && equivalent == false; i++) { 315 rec = (DARecord)ret.elementAt(i); 316 Vector dascopes = rec.scopes; 317 318 int j, m = dascopes.size(); 319 320 for (j = 0; j < m; j++) { 321 String scope = (String)dascopes.elementAt(j); 322 323 if (!scopes.contains(scope)) { 324 continue outer; 325 326 } 327 } 328 329 equivalent = true; 330 } 331 332 // Make a new record if not equivalent. 333 334 if (!equivalent) { 335 rec = new DATable.DARecord(); 336 rec.scopes = (Vector)scopes.clone(); 337 338 ret.addElement(rec); 339 340 } 341 342 343 // Add to record. Optimize, by putting the local address at the 344 // beginning of the vector. 345 346 Vector interfaces = conf.getInterfaces(); 347 348 if (interfaces.contains(addr)) { 349 rec.daAddresses.insertElementAt(addr, 0); 350 351 } else { 352 rec.daAddresses.addElement(addr); 353 354 } 355 356 return true; 357 } 358 359 /** 360 * Validate the scope names. We check that they are all strings, 361 * that none are the empty string. In addition, we collate to 362 * remove duplicates, and lower case. 363 */ 364 365 static void validateScopes(Vector scopes, Locale locale) 366 throws ServiceLocationException { 367 368 // Check for empty vector. 369 370 if (scopes == null || scopes.size() <= 0) { 371 throw 372 new ServiceLocationException( 373 ServiceLocationException.PARSE_ERROR, 374 "no_scope_vector", 375 new Object[0]); 376 } 377 378 // Check for all strings and none empty. 379 380 int i; 381 Hashtable ht = new Hashtable(); 382 383 for (i = 0; i < scopes.size(); i++) { 384 Object o = scopes.elementAt(i); 385 386 if (!(o instanceof String)) { 387 throw 388 new ServiceLocationException( 389 ServiceLocationException.PARSE_ERROR, 390 "non_string_element", 391 new Object[] {scopes}); 392 } 393 394 String str = (String)o; 395 396 if (str.length() <= 0) { 397 throw 398 new ServiceLocationException( 399 ServiceLocationException.PARSE_ERROR, 400 "null_element", 401 new Object[] {scopes}); 402 } 403 404 // Lower case, trim. 405 406 str = str.toLowerCase(locale).trim(); 407 408 // Squeeze out spaces. 409 410 StringBuffer buf = new StringBuffer(); 411 StringTokenizer tk = 412 new StringTokenizer(str, ServiceLocationAttribute.WHITESPACE); 413 String tok = null; 414 415 while (tk.hasMoreTokens()) { 416 417 // Add a single embedded whitespace for each group found. 418 419 if (tok != null) { 420 buf.append(" "); 421 422 } 423 424 tok = tk.nextToken(); 425 buf.append(tok); 426 } 427 428 str = buf.toString(); 429 430 // If it wasn't already seen, put it into the hashtable. 431 432 if (ht.get(str) == null) { 433 ht.put(str, str); 434 scopes.setElementAt(str, i); 435 436 } else { 437 /* 438 * Must decrement the index 'i' otherwise the next iteration 439 * around the loop will miss the element immediately after 440 * the element removed. 441 * 442 * WARNING: Do not use 'i' again until the loop has 443 * iterated as it may, after decrementing, 444 * be negative. 445 */ 446 scopes.removeElementAt(i); 447 i--; 448 continue; 449 } 450 } 451 } 452 453 } 454