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