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