17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
59a70fc3bSMark J. Nelson  * Common Development and Distribution License (the "License").
69a70fc3bSMark J. Nelson  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
227c478bd9Sstevel@tonic-gate  * Copyright (c) 1999 by Sun Microsystems, Inc.
237c478bd9Sstevel@tonic-gate  * All rights reserved.
247c478bd9Sstevel@tonic-gate  *
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate //  ServiceStoreFactory.java: Factory for creating ServiceStore objects.
287c478bd9Sstevel@tonic-gate //  Author:           James Kempf
297c478bd9Sstevel@tonic-gate //  Created On:       Fri Apr 17 12:14:12 1998
307c478bd9Sstevel@tonic-gate //  Last Modified By: James Kempf
317c478bd9Sstevel@tonic-gate //  Last Modified On: Mon Jan  4 15:26:34 1999
327c478bd9Sstevel@tonic-gate //  Update Count:     34
337c478bd9Sstevel@tonic-gate //
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate package com.sun.slp;
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate import java.util.*;
387c478bd9Sstevel@tonic-gate import java.io.*;
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate /**
417c478bd9Sstevel@tonic-gate  * The ServiceStoreFactory provides a way to obtain a ServiceStore
427c478bd9Sstevel@tonic-gate  * object. The exact implementation will depend on how the
437c478bd9Sstevel@tonic-gate  * DA/slpd is configured. It could be an in-memory database,
447c478bd9Sstevel@tonic-gate  * a connection to an LDAP server, or a persistent object
457c478bd9Sstevel@tonic-gate  * database.
467c478bd9Sstevel@tonic-gate  *
477c478bd9Sstevel@tonic-gate  * @author James Kempf
487c478bd9Sstevel@tonic-gate  */
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate class ServiceStoreFactory extends Object {
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate     private static final String DEFAULT_SERVICE_STORE =
537c478bd9Sstevel@tonic-gate 	"com.sun.slp.ServiceStoreInMemory";
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate     private static final String SERVICE_STORE_PROPERTY =
567c478bd9Sstevel@tonic-gate 	"sun.net.slp.serviceStoreClass";
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate     // Comment characters for deserialization.
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate     final private static char COMMENT_CHAR1 = '#';
617c478bd9Sstevel@tonic-gate     final private static char COMMENT_CHAR2 = ';';
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate     // Character for URL list separator.
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate     final private static String URL_LIST_SEP = ", ";
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate     // Identifies scopes pseudo-attribute.
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate     final private static String SCOPES_ATTR_ID = "scopes";
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate     /**
727c478bd9Sstevel@tonic-gate      * Return the ServiceStore for the SLP agent.
737c478bd9Sstevel@tonic-gate      *
747c478bd9Sstevel@tonic-gate      * @return An object supporting the ServiceStore interface.
757c478bd9Sstevel@tonic-gate      * @exception ServiceLocationException Thrown
767c478bd9Sstevel@tonic-gate      *			if the ServiceStore object can't be
777c478bd9Sstevel@tonic-gate      *			created or if the
787c478bd9Sstevel@tonic-gate      *			class implementing the ServiceStore required
797c478bd9Sstevel@tonic-gate      *			a network connnection (for example, an LDAP
807c478bd9Sstevel@tonic-gate      *			server) and the connection couldn't be made.
817c478bd9Sstevel@tonic-gate      */
827c478bd9Sstevel@tonic-gate 
createServiceStore()837c478bd9Sstevel@tonic-gate     static ServiceStore createServiceStore()
847c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate 	return createServiceStoreFromProperty(SERVICE_STORE_PROPERTY);
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate     }
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate     // Create the appropriate ServiceStore object from the property.
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate     private static ServiceStore
createServiceStoreFromProperty(String property)937c478bd9Sstevel@tonic-gate 	createServiceStoreFromProperty(String property)
947c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 	Properties props = System.getProperties();
977c478bd9Sstevel@tonic-gate 	String storeClassName =
987c478bd9Sstevel@tonic-gate 	    props.getProperty(property,
997c478bd9Sstevel@tonic-gate 			      DEFAULT_SERVICE_STORE);
1007c478bd9Sstevel@tonic-gate 	Class storeClass = null;
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 	try {
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 	    storeClass = Class.forName(storeClassName);
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 	} catch (ClassNotFoundException ex) {
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	    throw
1097c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
1107c478bd9Sstevel@tonic-gate 				ServiceLocationException.INTERNAL_SYSTEM_ERROR,
1117c478bd9Sstevel@tonic-gate 				"ssf_no_class",
1127c478bd9Sstevel@tonic-gate 				new Object[] {storeClassName});
1137c478bd9Sstevel@tonic-gate 	}
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 	ServiceStore store = null;
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 	try {
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate 	    store = (ServiceStore)storeClass.newInstance();
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 	} catch (InstantiationException ex) {
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	    throw
1247c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
1257c478bd9Sstevel@tonic-gate 				ServiceLocationException.INTERNAL_SYSTEM_ERROR,
1267c478bd9Sstevel@tonic-gate 				"ssf_inst_ex",
1277c478bd9Sstevel@tonic-gate 				new Object[] {
1287c478bd9Sstevel@tonic-gate 		    storeClassName,
1297c478bd9Sstevel@tonic-gate 			ex.getMessage()});
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 	} catch (IllegalAccessException ex) {
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 	    throw
1347c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
1357c478bd9Sstevel@tonic-gate 				ServiceLocationException.INTERNAL_SYSTEM_ERROR,
1367c478bd9Sstevel@tonic-gate 				"ssf_ill_ex",
1377c478bd9Sstevel@tonic-gate 				new Object[] {
1387c478bd9Sstevel@tonic-gate 		    storeClassName,
1397c478bd9Sstevel@tonic-gate 			ex.getMessage()});
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	} catch (ClassCastException ex) {
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 	    throw
1447c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
1457c478bd9Sstevel@tonic-gate 				ServiceLocationException.INTERNAL_SYSTEM_ERROR,
1467c478bd9Sstevel@tonic-gate 				"ssf_class_cast",
1477c478bd9Sstevel@tonic-gate 				new Object[] {storeClassName});
1487c478bd9Sstevel@tonic-gate 	}
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	return store;
1517c478bd9Sstevel@tonic-gate     }
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate     /**
1547c478bd9Sstevel@tonic-gate      * Deserialize a service store from the open stream.
1557c478bd9Sstevel@tonic-gate      *
1567c478bd9Sstevel@tonic-gate      * @param is The object input stream for the service store.
1577c478bd9Sstevel@tonic-gate      * @return ServiceStore deserialized from the stream.
1587c478bd9Sstevel@tonic-gate      * @exception ServiceLocationException If anything goes
1597c478bd9Sstevel@tonic-gate      *				wrong with the deserialization.
1607c478bd9Sstevel@tonic-gate      */
1617c478bd9Sstevel@tonic-gate 
deserializeServiceStore(BufferedReader is)1627c478bd9Sstevel@tonic-gate     static ServiceStore deserializeServiceStore(BufferedReader is)
1637c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	ServiceStore ss = new ServiceStoreInMemory();
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	try {
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	    deserialize(is, ss);
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 	} catch (IOException ex) {
1727c478bd9Sstevel@tonic-gate 	    throw
1737c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
1747c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
1757c478bd9Sstevel@tonic-gate 				"ssf_io_deser",
1767c478bd9Sstevel@tonic-gate 				new Object[] {ex.getMessage()});
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	}
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	return ss;
1817c478bd9Sstevel@tonic-gate     }
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate     // Read the service store in the standard format from the input
1847c478bd9Sstevel@tonic-gate 
deserialize(BufferedReader in, ServiceStore store)1857c478bd9Sstevel@tonic-gate     private static void deserialize(BufferedReader in, ServiceStore store)
1867c478bd9Sstevel@tonic-gate 	throws IOException, ServiceLocationException {
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 	SLPConfig conf = SLPConfig.getSLPConfig();
1897c478bd9Sstevel@tonic-gate 	int linecount = 0;
1907c478bd9Sstevel@tonic-gate 	int scopeLinenum = 0;
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	// Parse input file until no bytes left.
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	while (in.ready()) {
1957c478bd9Sstevel@tonic-gate 	    linecount++;
1967c478bd9Sstevel@tonic-gate 	    String line = in.readLine().trim();
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	    // Skip any empty lines at this level.
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	    if (line.length() <= 0) {
2017c478bd9Sstevel@tonic-gate 		continue;
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 	    }
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	    char cc = line.charAt(0);
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	    // If initial character is "#" or ";", ignore the line.
2087c478bd9Sstevel@tonic-gate 	    //  It's a comment. Also if the line is empty.
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	    if (cc == COMMENT_CHAR1 ||
2117c478bd9Sstevel@tonic-gate 		cc == COMMENT_CHAR2) {
2127c478bd9Sstevel@tonic-gate 		continue;
2137c478bd9Sstevel@tonic-gate 	    }
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 	    // At this level, the line must be a URL registration,
2167c478bd9Sstevel@tonic-gate 	    //  with format:
2177c478bd9Sstevel@tonic-gate 	    //
2187c478bd9Sstevel@tonic-gate 	    // service-url ", " language ", " lifetime [ ", " type ]
2197c478bd9Sstevel@tonic-gate 	    //
2207c478bd9Sstevel@tonic-gate 	    //
2217c478bd9Sstevel@tonic-gate 	    //  We allow arbitrary whitespace around commas.
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 	    StringTokenizer tk = new StringTokenizer(line, URL_LIST_SEP);
2247c478bd9Sstevel@tonic-gate 	    String surl = null;
2257c478bd9Sstevel@tonic-gate 	    String slang = null;
2267c478bd9Sstevel@tonic-gate 	    String slifetime = null;
2277c478bd9Sstevel@tonic-gate 	    String sType = null;
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	    if (tk.hasMoreTokens()) {
2307c478bd9Sstevel@tonic-gate 		surl = tk.nextToken().trim();
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 		if (tk.hasMoreTokens()) {
2337c478bd9Sstevel@tonic-gate 		    slang = tk.nextToken().trim();
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 		    if (tk.hasMoreTokens()) {
2367c478bd9Sstevel@tonic-gate 			slifetime = tk.nextToken().trim();
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 			if (tk.hasMoreTokens()) {
2397c478bd9Sstevel@tonic-gate 			    sType = tk.nextToken().trim();
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 			    if (tk.hasMoreTokens()) {
2427c478bd9Sstevel@tonic-gate 				slang = null;
2437c478bd9Sstevel@tonic-gate 					// should be nothing more on the line.
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 			    }
2467c478bd9Sstevel@tonic-gate 			}
2477c478bd9Sstevel@tonic-gate 		    }
2487c478bd9Sstevel@tonic-gate 		}
2497c478bd9Sstevel@tonic-gate 	    }
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	    // Check for errors.
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	    if (surl == null || slifetime == null || slang == null) {
2547c478bd9Sstevel@tonic-gate 		throw
2557c478bd9Sstevel@tonic-gate 		    new ServiceLocationException(
2567c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
2577c478bd9Sstevel@tonic-gate 				"ssf_not_valid_url",
2587c478bd9Sstevel@tonic-gate 				new Object[] {line});
2597c478bd9Sstevel@tonic-gate 	    }
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 	    // Create the service: URL.
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	    Locale locale = SLPConfig.langTagToLocale(slang);
2647c478bd9Sstevel@tonic-gate 	    ServiceURL url = null;
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	    try {
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 		int lifetime = Integer.parseInt(slifetime);
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 		// If lifetime is maximum, then set to LIFETIME_PERMANENT.
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 		if (lifetime == ServiceURL.LIFETIME_MAXIMUM) {
2737c478bd9Sstevel@tonic-gate 		    lifetime = ServiceURL.LIFETIME_PERMANENT;
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 		}
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 		url = new ServiceURL(surl, lifetime);
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 		if (sType != null) {
280*55fea89dSDan Cross 
2817c478bd9Sstevel@tonic-gate 		    // Check if it's OK for this service URL.
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 		    ServiceType utype = url.getServiceType();
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 		    if (utype.isServiceURL()) {
2867c478bd9Sstevel@tonic-gate 			conf.writeLog("ssf_set_servc_err",
2877c478bd9Sstevel@tonic-gate 				      new Object[] {
2887c478bd9Sstevel@tonic-gate 			    surl,
2897c478bd9Sstevel@tonic-gate 				utype});
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 		    } else {
2927c478bd9Sstevel@tonic-gate 			ServiceType t = new ServiceType(sType);
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 			if (!t.isServiceURL() &&
2957c478bd9Sstevel@tonic-gate 			    !t.equals(url.getServiceType())) {
2967c478bd9Sstevel@tonic-gate 			    url.setServiceType(t);
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 			}
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 		    }
3017c478bd9Sstevel@tonic-gate 		}
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	    } catch (NumberFormatException ex) {
3047c478bd9Sstevel@tonic-gate 		throw
3057c478bd9Sstevel@tonic-gate 		    new ServiceLocationException(
3067c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
3077c478bd9Sstevel@tonic-gate 				"ssf_not_valid_lifetime",
3087c478bd9Sstevel@tonic-gate 				new Object[] {
3097c478bd9Sstevel@tonic-gate 			slifetime, new Integer(linecount)});
310*55fea89dSDan Cross 
3117c478bd9Sstevel@tonic-gate 	    } catch (IllegalArgumentException ex) {
3127c478bd9Sstevel@tonic-gate 		throw
3137c478bd9Sstevel@tonic-gate 		    new ServiceLocationException(
3147c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
3157c478bd9Sstevel@tonic-gate 				"ssf_syntax_err",
3167c478bd9Sstevel@tonic-gate 				new Object[] {
3177c478bd9Sstevel@tonic-gate 			ex.getMessage(), new Integer(linecount)});
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	    }
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	    // Get attributes. Format should be:
3227c478bd9Sstevel@tonic-gate 	    //
3237c478bd9Sstevel@tonic-gate 	    //      attr-line    = attr-assign | keyword
3247c478bd9Sstevel@tonic-gate 	    //	attr-assign  = attr-id "=" attrval-list
3257c478bd9Sstevel@tonic-gate 	    //	keyword      = attr-id
3267c478bd9Sstevel@tonic-gate 	    //	attrval-list = attrval | attrval ", " attrval-list
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	    Vector attrs = new Vector();
3297c478bd9Sstevel@tonic-gate 	    Hashtable ht = new Hashtable();
3307c478bd9Sstevel@tonic-gate 	    ServiceLocationAttribute scopeAttr = null;
3317c478bd9Sstevel@tonic-gate 	    boolean firstLine = true;
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	    try {
3347c478bd9Sstevel@tonic-gate 		while (in.ready()) {
3357c478bd9Sstevel@tonic-gate 		    linecount++;
3367c478bd9Sstevel@tonic-gate 		    line = in.readLine();
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 		    // Empty line indicates we're done with attributes.
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 		    if (line.length() <= 0) {
3417c478bd9Sstevel@tonic-gate 			break;
3427c478bd9Sstevel@tonic-gate 		    }
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 		    // Format the line for creating. Check whether it's a
3457c478bd9Sstevel@tonic-gate 		    // keyword or not.
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 		    if (line.indexOf("=") != -1) {
3487c478bd9Sstevel@tonic-gate 			line = "(" + line + ")";
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 		    }
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 		    // Create the attribute from the string.
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 		    ServiceLocationAttribute attr =
3557c478bd9Sstevel@tonic-gate 			new ServiceLocationAttribute(line, false);
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 		    // If this is the scope attribute, save until later.
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 		    if (firstLine) {
3607c478bd9Sstevel@tonic-gate 			firstLine = false;
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 			if (attr.getId().equalsIgnoreCase(SCOPES_ATTR_ID)) {
3637c478bd9Sstevel@tonic-gate 			    scopeAttr = attr;
3647c478bd9Sstevel@tonic-gate 			    continue; // do NOT save as a regular attribute.
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 			}
3677c478bd9Sstevel@tonic-gate 		    }
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 		    ServiceLocationAttribute.mergeDuplicateAttributes(attr,
3707c478bd9Sstevel@tonic-gate 								      ht,
3717c478bd9Sstevel@tonic-gate 								      attrs,
3727c478bd9Sstevel@tonic-gate 								      false);
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 		}
3757c478bd9Sstevel@tonic-gate 	    } catch (ServiceLocationException e) {
3767c478bd9Sstevel@tonic-gate 		// tack on the line count
3777c478bd9Sstevel@tonic-gate 		e.makeAddendum(" (line " + linecount + ")");
3787c478bd9Sstevel@tonic-gate 		throw e;
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	    }
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	    Vector scopes = null;
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	    // Use scopes we've been configured with if none.
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	    if (scopeAttr == null) {
3877c478bd9Sstevel@tonic-gate 		scopes = conf.getSAConfiguredScopes();
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	    } else {
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 		scopes = (Vector)scopeAttr.getValues();
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 		try {
3947c478bd9Sstevel@tonic-gate 		    // Unescape scope strings.
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 		    SLPHeaderV2.unescapeScopeStrings(scopes);
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 		    // Validate, lower case scope names.
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 		    DATable.validateScopes(scopes, locale);
401*55fea89dSDan Cross 
4027c478bd9Sstevel@tonic-gate 		} catch (ServiceLocationException e) {
4037c478bd9Sstevel@tonic-gate 		    e.makeAddendum(" (line " + scopeLinenum + ")");
4047c478bd9Sstevel@tonic-gate 		    throw e;
4057c478bd9Sstevel@tonic-gate 		}
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 	    }
408*55fea89dSDan Cross 
4097c478bd9Sstevel@tonic-gate 	    // We've got the attributes, the service URL, scope, and
4107c478bd9Sstevel@tonic-gate 	    //  locale, so add a record. Note that any crypto is
4117c478bd9Sstevel@tonic-gate 	    //  added when the registration is actually done.
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	    store.register(url, attrs, scopes, locale, null, null);
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	    // Create a CSrvReg for forwarding
4167c478bd9Sstevel@tonic-gate 	    CSrvReg creg = new CSrvReg(true, locale, url, scopes,
4177c478bd9Sstevel@tonic-gate 				       attrs, null, null);
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	    ServerDATable daTable = ServerDATable.getServerDATable();
4207c478bd9Sstevel@tonic-gate 	    daTable.forwardSAMessage(creg, conf.getLoopback());
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	}
4237c478bd9Sstevel@tonic-gate     }
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate     // Write the service store in the standard format to the output
4267c478bd9Sstevel@tonic-gate     // stream.
4277c478bd9Sstevel@tonic-gate 
serialize(BufferedWriter out, ServiceStore store)4287c478bd9Sstevel@tonic-gate     static void serialize(BufferedWriter out, ServiceStore store)
4297c478bd9Sstevel@tonic-gate 	throws IOException, ServiceLocationException {
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	Enumeration recs = store.getServiceRecordsByScope(null);
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	while (recs.hasMoreElements()) {
4347c478bd9Sstevel@tonic-gate 	    ServiceStore.ServiceRecord rec =
4357c478bd9Sstevel@tonic-gate 		(ServiceStore.ServiceRecord)recs.nextElement();
4367c478bd9Sstevel@tonic-gate 	    ServiceURL url = rec.getServiceURL();
4377c478bd9Sstevel@tonic-gate 	    String surl = url.toString();
4387c478bd9Sstevel@tonic-gate 	    Vector attrs = (Vector)rec.getAttrList().clone();
4397c478bd9Sstevel@tonic-gate 	    Locale locale = rec.getLocale();
4407c478bd9Sstevel@tonic-gate 	    Vector scopes = rec.getScopes();
4417c478bd9Sstevel@tonic-gate 	    StringBuffer line = new StringBuffer();
442*55fea89dSDan Cross 
4437c478bd9Sstevel@tonic-gate 	    // Compose the registration line.
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	    line.append(surl);
4467c478bd9Sstevel@tonic-gate 	    line.append(", ");
4477c478bd9Sstevel@tonic-gate 	    line.append(SLPConfig.localeToLangTag(locale));
4487c478bd9Sstevel@tonic-gate 	    line.append(", ");
4497c478bd9Sstevel@tonic-gate 	    line.append(Integer.toString(url.getLifetime()));
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 	    // Put out the service type and naming authority if the
4527c478bd9Sstevel@tonic-gate 	    //  URL is not a service URL.
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	    if (!surl.startsWith(Defaults.SERVICE_PREFIX)) {
4557c478bd9Sstevel@tonic-gate 		ServiceType type = url.getServiceType();
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 		line.append(", ");
4587c478bd9Sstevel@tonic-gate 		line.append(type.toString());
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	    }
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 	    // Write out line.
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 	    out.write(line.toString(), 0, line.length());
4657c478bd9Sstevel@tonic-gate 	    out.newLine();
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 	    // Zero line buffer.
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	    line.setLength(0);
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	    // Insert a scope attribute, if the scope isn't simply "DEFAULT".
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 	    if (scopes.size() > 1 &&
4747c478bd9Sstevel@tonic-gate 		!Defaults.DEFAULT_SCOPE.equals((String)scopes.elementAt(0))) {
4757c478bd9Sstevel@tonic-gate 		attrs.insertElementAt(
4767c478bd9Sstevel@tonic-gate 				new ServiceLocationAttribute(SCOPES_ATTR_ID,
4777c478bd9Sstevel@tonic-gate 							     scopes),
4787c478bd9Sstevel@tonic-gate 				0);
4797c478bd9Sstevel@tonic-gate 	    }
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	    // Write out the attributes.
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 	    int i, n = attrs.size();
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	    for (i = 0; i < n; i++) {
4867c478bd9Sstevel@tonic-gate 		ServiceLocationAttribute attr =
4877c478bd9Sstevel@tonic-gate 		    (ServiceLocationAttribute)attrs.elementAt(i);
4887c478bd9Sstevel@tonic-gate 		Vector vals = attr.getValues();
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 		line.append(
4917c478bd9Sstevel@tonic-gate 		ServiceLocationAttribute.escapeAttributeString(attr.getId(),
4927c478bd9Sstevel@tonic-gate 							       false));
4937c478bd9Sstevel@tonic-gate 		// Add the escaped values.
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 		if (vals != null) {
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 		    line.append("=");
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 		    int j, m = vals.size();
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 		    for (j = 0; j < m; j++) {
5027c478bd9Sstevel@tonic-gate 			Object v = vals.elementAt(j);
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 			if (j > 0) {
5057c478bd9Sstevel@tonic-gate 			    line.append(", ");
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 			}
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 			line.append(ServiceLocationAttribute.escapeValue(v));
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 		    }
5127c478bd9Sstevel@tonic-gate 		}
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 		out.write(line.toString(), 0, line.length());
5157c478bd9Sstevel@tonic-gate 		out.newLine();
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 		// Zero out string buffer.
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 		line.setLength(0);
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	    }
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 	    // End of registration.
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	    out.newLine();
5267c478bd9Sstevel@tonic-gate 	}
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	out.flush();
5297c478bd9Sstevel@tonic-gate     }
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate }
532