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) 1999 by Sun Microsystems, Inc. 23 * All rights reserved. 24 * 25 */ 26 27 // ServiceStoreFactory.java: Factory for creating ServiceStore objects. 28 // Author: James Kempf 29 // Created On: Fri Apr 17 12:14:12 1998 30 // Last Modified By: James Kempf 31 // Last Modified On: Mon Jan 4 15:26:34 1999 32 // Update Count: 34 33 // 34 35 package com.sun.slp; 36 37 import java.util.*; 38 import java.io.*; 39 40 /** 41 * The ServiceStoreFactory provides a way to obtain a ServiceStore 42 * object. The exact implementation will depend on how the 43 * DA/slpd is configured. It could be an in-memory database, 44 * a connection to an LDAP server, or a persistent object 45 * database. 46 * 47 * @author James Kempf 48 */ 49 50 class ServiceStoreFactory extends Object { 51 52 private static final String DEFAULT_SERVICE_STORE = 53 "com.sun.slp.ServiceStoreInMemory"; 54 55 private static final String SERVICE_STORE_PROPERTY = 56 "sun.net.slp.serviceStoreClass"; 57 58 // Comment characters for deserialization. 59 60 final private static char COMMENT_CHAR1 = '#'; 61 final private static char COMMENT_CHAR2 = ';'; 62 63 // Character for URL list separator. 64 65 final private static String URL_LIST_SEP = ", "; 66 67 // Identifies scopes pseudo-attribute. 68 69 final private static String SCOPES_ATTR_ID = "scopes"; 70 71 /** 72 * Return the ServiceStore for the SLP agent. 73 * 74 * @return An object supporting the ServiceStore interface. 75 * @exception ServiceLocationException Thrown 76 * if the ServiceStore object can't be 77 * created or if the 78 * class implementing the ServiceStore required 79 * a network connnection (for example, an LDAP 80 * server) and the connection couldn't be made. 81 */ 82 83 static ServiceStore createServiceStore() 84 throws ServiceLocationException { 85 86 return createServiceStoreFromProperty(SERVICE_STORE_PROPERTY); 87 88 } 89 90 // Create the appropriate ServiceStore object from the property. 91 92 private static ServiceStore 93 createServiceStoreFromProperty(String property) 94 throws ServiceLocationException { 95 96 Properties props = System.getProperties(); 97 String storeClassName = 98 props.getProperty(property, 99 DEFAULT_SERVICE_STORE); 100 Class storeClass = null; 101 102 try { 103 104 storeClass = Class.forName(storeClassName); 105 106 } catch (ClassNotFoundException ex) { 107 108 throw 109 new ServiceLocationException( 110 ServiceLocationException.INTERNAL_SYSTEM_ERROR, 111 "ssf_no_class", 112 new Object[] {storeClassName}); 113 } 114 115 ServiceStore store = null; 116 117 try { 118 119 store = (ServiceStore)storeClass.newInstance(); 120 121 } catch (InstantiationException ex) { 122 123 throw 124 new ServiceLocationException( 125 ServiceLocationException.INTERNAL_SYSTEM_ERROR, 126 "ssf_inst_ex", 127 new Object[] { 128 storeClassName, 129 ex.getMessage()}); 130 131 } catch (IllegalAccessException ex) { 132 133 throw 134 new ServiceLocationException( 135 ServiceLocationException.INTERNAL_SYSTEM_ERROR, 136 "ssf_ill_ex", 137 new Object[] { 138 storeClassName, 139 ex.getMessage()}); 140 141 } catch (ClassCastException ex) { 142 143 throw 144 new ServiceLocationException( 145 ServiceLocationException.INTERNAL_SYSTEM_ERROR, 146 "ssf_class_cast", 147 new Object[] {storeClassName}); 148 } 149 150 return store; 151 } 152 153 /** 154 * Deserialize a service store from the open stream. 155 * 156 * @param is The object input stream for the service store. 157 * @return ServiceStore deserialized from the stream. 158 * @exception ServiceLocationException If anything goes 159 * wrong with the deserialization. 160 */ 161 162 static ServiceStore deserializeServiceStore(BufferedReader is) 163 throws ServiceLocationException { 164 165 ServiceStore ss = new ServiceStoreInMemory(); 166 167 try { 168 169 deserialize(is, ss); 170 171 } catch (IOException ex) { 172 throw 173 new ServiceLocationException( 174 ServiceLocationException.PARSE_ERROR, 175 "ssf_io_deser", 176 new Object[] {ex.getMessage()}); 177 178 } 179 180 return ss; 181 } 182 183 // Read the service store in the standard format from the input 184 185 private static void deserialize(BufferedReader in, ServiceStore store) 186 throws IOException, ServiceLocationException { 187 188 SLPConfig conf = SLPConfig.getSLPConfig(); 189 int linecount = 0; 190 int scopeLinenum = 0; 191 192 // Parse input file until no bytes left. 193 194 while (in.ready()) { 195 linecount++; 196 String line = in.readLine().trim(); 197 198 // Skip any empty lines at this level. 199 200 if (line.length() <= 0) { 201 continue; 202 203 } 204 205 char cc = line.charAt(0); 206 207 // If initial character is "#" or ";", ignore the line. 208 // It's a comment. Also if the line is empty. 209 210 if (cc == COMMENT_CHAR1 || 211 cc == COMMENT_CHAR2) { 212 continue; 213 } 214 215 // At this level, the line must be a URL registration, 216 // with format: 217 // 218 // service-url ", " language ", " lifetime [ ", " type ] 219 // 220 // 221 // We allow arbitrary whitespace around commas. 222 223 StringTokenizer tk = new StringTokenizer(line, URL_LIST_SEP); 224 String surl = null; 225 String slang = null; 226 String slifetime = null; 227 String sType = null; 228 229 if (tk.hasMoreTokens()) { 230 surl = tk.nextToken().trim(); 231 232 if (tk.hasMoreTokens()) { 233 slang = tk.nextToken().trim(); 234 235 if (tk.hasMoreTokens()) { 236 slifetime = tk.nextToken().trim(); 237 238 if (tk.hasMoreTokens()) { 239 sType = tk.nextToken().trim(); 240 241 if (tk.hasMoreTokens()) { 242 slang = null; 243 // should be nothing more on the line. 244 245 } 246 } 247 } 248 } 249 } 250 251 // Check for errors. 252 253 if (surl == null || slifetime == null || slang == null) { 254 throw 255 new ServiceLocationException( 256 ServiceLocationException.PARSE_ERROR, 257 "ssf_not_valid_url", 258 new Object[] {line}); 259 } 260 261 // Create the service: URL. 262 263 Locale locale = SLPConfig.langTagToLocale(slang); 264 ServiceURL url = null; 265 266 try { 267 268 int lifetime = Integer.parseInt(slifetime); 269 270 // If lifetime is maximum, then set to LIFETIME_PERMANENT. 271 272 if (lifetime == ServiceURL.LIFETIME_MAXIMUM) { 273 lifetime = ServiceURL.LIFETIME_PERMANENT; 274 275 } 276 277 url = new ServiceURL(surl, lifetime); 278 279 if (sType != null) { 280 281 // Check if it's OK for this service URL. 282 283 ServiceType utype = url.getServiceType(); 284 285 if (utype.isServiceURL()) { 286 conf.writeLog("ssf_set_servc_err", 287 new Object[] { 288 surl, 289 utype}); 290 291 } else { 292 ServiceType t = new ServiceType(sType); 293 294 if (!t.isServiceURL() && 295 !t.equals(url.getServiceType())) { 296 url.setServiceType(t); 297 298 } 299 300 } 301 } 302 303 } catch (NumberFormatException ex) { 304 throw 305 new ServiceLocationException( 306 ServiceLocationException.PARSE_ERROR, 307 "ssf_not_valid_lifetime", 308 new Object[] { 309 slifetime, new Integer(linecount)}); 310 311 } catch (IllegalArgumentException ex) { 312 throw 313 new ServiceLocationException( 314 ServiceLocationException.PARSE_ERROR, 315 "ssf_syntax_err", 316 new Object[] { 317 ex.getMessage(), new Integer(linecount)}); 318 319 } 320 321 // Get attributes. Format should be: 322 // 323 // attr-line = attr-assign | keyword 324 // attr-assign = attr-id "=" attrval-list 325 // keyword = attr-id 326 // attrval-list = attrval | attrval ", " attrval-list 327 328 Vector attrs = new Vector(); 329 Hashtable ht = new Hashtable(); 330 ServiceLocationAttribute scopeAttr = null; 331 boolean firstLine = true; 332 333 try { 334 while (in.ready()) { 335 linecount++; 336 line = in.readLine(); 337 338 // Empty line indicates we're done with attributes. 339 340 if (line.length() <= 0) { 341 break; 342 } 343 344 // Format the line for creating. Check whether it's a 345 // keyword or not. 346 347 if (line.indexOf("=") != -1) { 348 line = "(" + line + ")"; 349 350 } 351 352 // Create the attribute from the string. 353 354 ServiceLocationAttribute attr = 355 new ServiceLocationAttribute(line, false); 356 357 // If this is the scope attribute, save until later. 358 359 if (firstLine) { 360 firstLine = false; 361 362 if (attr.getId().equalsIgnoreCase(SCOPES_ATTR_ID)) { 363 scopeAttr = attr; 364 continue; // do NOT save as a regular attribute. 365 366 } 367 } 368 369 ServiceLocationAttribute.mergeDuplicateAttributes(attr, 370 ht, 371 attrs, 372 false); 373 374 } 375 } catch (ServiceLocationException e) { 376 // tack on the line count 377 e.makeAddendum(" (line " + linecount + ")"); 378 throw e; 379 380 } 381 382 Vector scopes = null; 383 384 // Use scopes we've been configured with if none. 385 386 if (scopeAttr == null) { 387 scopes = conf.getSAConfiguredScopes(); 388 389 } else { 390 391 scopes = (Vector)scopeAttr.getValues(); 392 393 try { 394 // Unescape scope strings. 395 396 SLPHeaderV2.unescapeScopeStrings(scopes); 397 398 // Validate, lower case scope names. 399 400 DATable.validateScopes(scopes, locale); 401 402 } catch (ServiceLocationException e) { 403 e.makeAddendum(" (line " + scopeLinenum + ")"); 404 throw e; 405 } 406 407 } 408 409 // We've got the attributes, the service URL, scope, and 410 // locale, so add a record. Note that any crypto is 411 // added when the registration is actually done. 412 413 store.register(url, attrs, scopes, locale, null, null); 414 415 // Create a CSrvReg for forwarding 416 CSrvReg creg = new CSrvReg(true, locale, url, scopes, 417 attrs, null, null); 418 419 ServerDATable daTable = ServerDATable.getServerDATable(); 420 daTable.forwardSAMessage(creg, conf.getLoopback()); 421 422 } 423 } 424 425 // Write the service store in the standard format to the output 426 // stream. 427 428 static void serialize(BufferedWriter out, ServiceStore store) 429 throws IOException, ServiceLocationException { 430 431 Enumeration recs = store.getServiceRecordsByScope(null); 432 433 while (recs.hasMoreElements()) { 434 ServiceStore.ServiceRecord rec = 435 (ServiceStore.ServiceRecord)recs.nextElement(); 436 ServiceURL url = rec.getServiceURL(); 437 String surl = url.toString(); 438 Vector attrs = (Vector)rec.getAttrList().clone(); 439 Locale locale = rec.getLocale(); 440 Vector scopes = rec.getScopes(); 441 StringBuffer line = new StringBuffer(); 442 443 // Compose the registration line. 444 445 line.append(surl); 446 line.append(", "); 447 line.append(SLPConfig.localeToLangTag(locale)); 448 line.append(", "); 449 line.append(Integer.toString(url.getLifetime())); 450 451 // Put out the service type and naming authority if the 452 // URL is not a service URL. 453 454 if (!surl.startsWith(Defaults.SERVICE_PREFIX)) { 455 ServiceType type = url.getServiceType(); 456 457 line.append(", "); 458 line.append(type.toString()); 459 460 } 461 462 // Write out line. 463 464 out.write(line.toString(), 0, line.length()); 465 out.newLine(); 466 467 // Zero line buffer. 468 469 line.setLength(0); 470 471 // Insert a scope attribute, if the scope isn't simply "DEFAULT". 472 473 if (scopes.size() > 1 && 474 !Defaults.DEFAULT_SCOPE.equals((String)scopes.elementAt(0))) { 475 attrs.insertElementAt( 476 new ServiceLocationAttribute(SCOPES_ATTR_ID, 477 scopes), 478 0); 479 } 480 481 // Write out the attributes. 482 483 int i, n = attrs.size(); 484 485 for (i = 0; i < n; i++) { 486 ServiceLocationAttribute attr = 487 (ServiceLocationAttribute)attrs.elementAt(i); 488 Vector vals = attr.getValues(); 489 490 line.append( 491 ServiceLocationAttribute.escapeAttributeString(attr.getId(), 492 false)); 493 // Add the escaped values. 494 495 if (vals != null) { 496 497 line.append("="); 498 499 int j, m = vals.size(); 500 501 for (j = 0; j < m; j++) { 502 Object v = vals.elementAt(j); 503 504 if (j > 0) { 505 line.append(", "); 506 507 } 508 509 line.append(ServiceLocationAttribute.escapeValue(v)); 510 511 } 512 } 513 514 out.write(line.toString(), 0, line.length()); 515 out.newLine(); 516 517 // Zero out string buffer. 518 519 line.setLength(0); 520 521 } 522 523 // End of registration. 524 525 out.newLine(); 526 } 527 528 out.flush(); 529 } 530 531 } 532