/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1999 by Sun Microsystems, Inc. * All rights reserved. * */ // ServiceStoreFactory.java: Factory for creating ServiceStore objects. // Author: James Kempf // Created On: Fri Apr 17 12:14:12 1998 // Last Modified By: James Kempf // Last Modified On: Mon Jan 4 15:26:34 1999 // Update Count: 34 // package com.sun.slp; import java.util.*; import java.io.*; /** * The ServiceStoreFactory provides a way to obtain a ServiceStore * object. The exact implementation will depend on how the * DA/slpd is configured. It could be an in-memory database, * a connection to an LDAP server, or a persistent object * database. * * @author James Kempf */ class ServiceStoreFactory extends Object { private static final String DEFAULT_SERVICE_STORE = "com.sun.slp.ServiceStoreInMemory"; private static final String SERVICE_STORE_PROPERTY = "sun.net.slp.serviceStoreClass"; // Comment characters for deserialization. final private static char COMMENT_CHAR1 = '#'; final private static char COMMENT_CHAR2 = ';'; // Character for URL list separator. final private static String URL_LIST_SEP = ", "; // Identifies scopes pseudo-attribute. final private static String SCOPES_ATTR_ID = "scopes"; /** * Return the ServiceStore for the SLP agent. * * @return An object supporting the ServiceStore interface. * @exception ServiceLocationException Thrown * if the ServiceStore object can't be * created or if the * class implementing the ServiceStore required * a network connnection (for example, an LDAP * server) and the connection couldn't be made. */ static ServiceStore createServiceStore() throws ServiceLocationException { return createServiceStoreFromProperty(SERVICE_STORE_PROPERTY); } // Create the appropriate ServiceStore object from the property. private static ServiceStore createServiceStoreFromProperty(String property) throws ServiceLocationException { Properties props = System.getProperties(); String storeClassName = props.getProperty(property, DEFAULT_SERVICE_STORE); Class storeClass = null; try { storeClass = Class.forName(storeClassName); } catch (ClassNotFoundException ex) { throw new ServiceLocationException( ServiceLocationException.INTERNAL_SYSTEM_ERROR, "ssf_no_class", new Object[] {storeClassName}); } ServiceStore store = null; try { store = (ServiceStore)storeClass.newInstance(); } catch (InstantiationException ex) { throw new ServiceLocationException( ServiceLocationException.INTERNAL_SYSTEM_ERROR, "ssf_inst_ex", new Object[] { storeClassName, ex.getMessage()}); } catch (IllegalAccessException ex) { throw new ServiceLocationException( ServiceLocationException.INTERNAL_SYSTEM_ERROR, "ssf_ill_ex", new Object[] { storeClassName, ex.getMessage()}); } catch (ClassCastException ex) { throw new ServiceLocationException( ServiceLocationException.INTERNAL_SYSTEM_ERROR, "ssf_class_cast", new Object[] {storeClassName}); } return store; } /** * Deserialize a service store from the open stream. * * @param is The object input stream for the service store. * @return ServiceStore deserialized from the stream. * @exception ServiceLocationException If anything goes * wrong with the deserialization. */ static ServiceStore deserializeServiceStore(BufferedReader is) throws ServiceLocationException { ServiceStore ss = new ServiceStoreInMemory(); try { deserialize(is, ss); } catch (IOException ex) { throw new ServiceLocationException( ServiceLocationException.PARSE_ERROR, "ssf_io_deser", new Object[] {ex.getMessage()}); } return ss; } // Read the service store in the standard format from the input private static void deserialize(BufferedReader in, ServiceStore store) throws IOException, ServiceLocationException { SLPConfig conf = SLPConfig.getSLPConfig(); int linecount = 0; int scopeLinenum = 0; // Parse input file until no bytes left. while (in.ready()) { linecount++; String line = in.readLine().trim(); // Skip any empty lines at this level. if (line.length() <= 0) { continue; } char cc = line.charAt(0); // If initial character is "#" or ";", ignore the line. // It's a comment. Also if the line is empty. if (cc == COMMENT_CHAR1 || cc == COMMENT_CHAR2) { continue; } // At this level, the line must be a URL registration, // with format: // // service-url ", " language ", " lifetime [ ", " type ] // // // We allow arbitrary whitespace around commas. StringTokenizer tk = new StringTokenizer(line, URL_LIST_SEP); String surl = null; String slang = null; String slifetime = null; String sType = null; if (tk.hasMoreTokens()) { surl = tk.nextToken().trim(); if (tk.hasMoreTokens()) { slang = tk.nextToken().trim(); if (tk.hasMoreTokens()) { slifetime = tk.nextToken().trim(); if (tk.hasMoreTokens()) { sType = tk.nextToken().trim(); if (tk.hasMoreTokens()) { slang = null; // should be nothing more on the line. } } } } } // Check for errors. if (surl == null || slifetime == null || slang == null) { throw new ServiceLocationException( ServiceLocationException.PARSE_ERROR, "ssf_not_valid_url", new Object[] {line}); } // Create the service: URL. Locale locale = SLPConfig.langTagToLocale(slang); ServiceURL url = null; try { int lifetime = Integer.parseInt(slifetime); // If lifetime is maximum, then set to LIFETIME_PERMANENT. if (lifetime == ServiceURL.LIFETIME_MAXIMUM) { lifetime = ServiceURL.LIFETIME_PERMANENT; } url = new ServiceURL(surl, lifetime); if (sType != null) { // Check if it's OK for this service URL. ServiceType utype = url.getServiceType(); if (utype.isServiceURL()) { conf.writeLog("ssf_set_servc_err", new Object[] { surl, utype}); } else { ServiceType t = new ServiceType(sType); if (!t.isServiceURL() && !t.equals(url.getServiceType())) { url.setServiceType(t); } } } } catch (NumberFormatException ex) { throw new ServiceLocationException( ServiceLocationException.PARSE_ERROR, "ssf_not_valid_lifetime", new Object[] { slifetime, new Integer(linecount)}); } catch (IllegalArgumentException ex) { throw new ServiceLocationException( ServiceLocationException.PARSE_ERROR, "ssf_syntax_err", new Object[] { ex.getMessage(), new Integer(linecount)}); } // Get attributes. Format should be: // // attr-line = attr-assign | keyword // attr-assign = attr-id "=" attrval-list // keyword = attr-id // attrval-list = attrval | attrval ", " attrval-list Vector attrs = new Vector(); Hashtable ht = new Hashtable(); ServiceLocationAttribute scopeAttr = null; boolean firstLine = true; try { while (in.ready()) { linecount++; line = in.readLine(); // Empty line indicates we're done with attributes. if (line.length() <= 0) { break; } // Format the line for creating. Check whether it's a // keyword or not. if (line.indexOf("=") != -1) { line = "(" + line + ")"; } // Create the attribute from the string. ServiceLocationAttribute attr = new ServiceLocationAttribute(line, false); // If this is the scope attribute, save until later. if (firstLine) { firstLine = false; if (attr.getId().equalsIgnoreCase(SCOPES_ATTR_ID)) { scopeAttr = attr; continue; // do NOT save as a regular attribute. } } ServiceLocationAttribute.mergeDuplicateAttributes(attr, ht, attrs, false); } } catch (ServiceLocationException e) { // tack on the line count e.makeAddendum(" (line " + linecount + ")"); throw e; } Vector scopes = null; // Use scopes we've been configured with if none. if (scopeAttr == null) { scopes = conf.getSAConfiguredScopes(); } else { scopes = (Vector)scopeAttr.getValues(); try { // Unescape scope strings. SLPHeaderV2.unescapeScopeStrings(scopes); // Validate, lower case scope names. DATable.validateScopes(scopes, locale); } catch (ServiceLocationException e) { e.makeAddendum(" (line " + scopeLinenum + ")"); throw e; } } // We've got the attributes, the service URL, scope, and // locale, so add a record. Note that any crypto is // added when the registration is actually done. store.register(url, attrs, scopes, locale, null, null); // Create a CSrvReg for forwarding CSrvReg creg = new CSrvReg(true, locale, url, scopes, attrs, null, null); ServerDATable daTable = ServerDATable.getServerDATable(); daTable.forwardSAMessage(creg, conf.getLoopback()); } } // Write the service store in the standard format to the output // stream. static void serialize(BufferedWriter out, ServiceStore store) throws IOException, ServiceLocationException { Enumeration recs = store.getServiceRecordsByScope(null); while (recs.hasMoreElements()) { ServiceStore.ServiceRecord rec = (ServiceStore.ServiceRecord)recs.nextElement(); ServiceURL url = rec.getServiceURL(); String surl = url.toString(); Vector attrs = (Vector)rec.getAttrList().clone(); Locale locale = rec.getLocale(); Vector scopes = rec.getScopes(); StringBuffer line = new StringBuffer(); // Compose the registration line. line.append(surl); line.append(", "); line.append(SLPConfig.localeToLangTag(locale)); line.append(", "); line.append(Integer.toString(url.getLifetime())); // Put out the service type and naming authority if the // URL is not a service URL. if (!surl.startsWith(Defaults.SERVICE_PREFIX)) { ServiceType type = url.getServiceType(); line.append(", "); line.append(type.toString()); } // Write out line. out.write(line.toString(), 0, line.length()); out.newLine(); // Zero line buffer. line.setLength(0); // Insert a scope attribute, if the scope isn't simply "DEFAULT". if (scopes.size() > 1 && !Defaults.DEFAULT_SCOPE.equals((String)scopes.elementAt(0))) { attrs.insertElementAt( new ServiceLocationAttribute(SCOPES_ATTR_ID, scopes), 0); } // Write out the attributes. int i, n = attrs.size(); for (i = 0; i < n; i++) { ServiceLocationAttribute attr = (ServiceLocationAttribute)attrs.elementAt(i); Vector vals = attr.getValues(); line.append( ServiceLocationAttribute.escapeAttributeString(attr.getId(), false)); // Add the escaped values. if (vals != null) { line.append("="); int j, m = vals.size(); for (j = 0; j < m; j++) { Object v = vals.elementAt(j); if (j > 0) { line.append(", "); } line.append(ServiceLocationAttribute.escapeValue(v)); } } out.write(line.toString(), 0, line.length()); out.newLine(); // Zero out string buffer. line.setLength(0); } // End of registration. out.newLine(); } out.flush(); } }