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
5*9a70fc3bSMark J. Nelson  * Common Development and Distribution License (the "License").
6*9a70fc3bSMark 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 2001,2003 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  *
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate //  DATable.java:     Interface for DATables.
287c478bd9Sstevel@tonic-gate //  Author:           James Kempf
297c478bd9Sstevel@tonic-gate //  Created On:       Mon May 11 13:46:02 1998
307c478bd9Sstevel@tonic-gate //  Last Modified By: James Kempf
317c478bd9Sstevel@tonic-gate //  Last Modified On: Mon Feb 22 15:47:37 1999
327c478bd9Sstevel@tonic-gate //  Update Count:     53
337c478bd9Sstevel@tonic-gate //
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate package com.sun.slp;
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate /**
397c478bd9Sstevel@tonic-gate  * DATable is an abstract class that provides the interface for DA
407c478bd9Sstevel@tonic-gate  * and scope discovery. A variety of implementations are possible.
417c478bd9Sstevel@tonic-gate  * The getDATable() method creates the right one from a subclass.
427c478bd9Sstevel@tonic-gate  *
437c478bd9Sstevel@tonic-gate  * @author James Kempf
447c478bd9Sstevel@tonic-gate  */
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate import java.util.*;
477c478bd9Sstevel@tonic-gate import java.net.*;
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate abstract class DATable extends Object {
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate     protected static DATable daTable;
527c478bd9Sstevel@tonic-gate     protected static SLPConfig conf;
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate     // System property naming the DATable implementation class to use.
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate     final static String DA_TABLE_CLASS_PROP = "sun.net.slp.DATableClass";
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate     // SA only scopes property.
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate     final static String SA_ONLY_SCOPES_PROP = "sun.net.slp.SAOnlyScopes";
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate     // Hashtable key for multicast scopes.
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate     final static String MULTICAST_KEY = "&&**^^MULTICASTxxxKEY^^**&&";
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate     // Hashtable key for DA equivalence classes.
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate     final static String UNICAST_KEY = "&&**^^UNICASTxxxKEY^^**&&";
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate     /**
717c478bd9Sstevel@tonic-gate      * A record for all DAs supporting exactly the same set of scopes.
727c478bd9Sstevel@tonic-gate      *
737c478bd9Sstevel@tonic-gate      * @author James Kempf
747c478bd9Sstevel@tonic-gate      */
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate     public static class DARecord extends Object {
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate 	// The scopes supported.
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate 	Vector scopes = null;		// String scope names
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate 	Vector daAddresses = new Vector();  // InetAddress DA addresses
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate     }
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate     /**
887c478bd9Sstevel@tonic-gate      * Return a hashtable containing two entries:
897c478bd9Sstevel@tonic-gate      *
907c478bd9Sstevel@tonic-gate      * MULTICAST_KEY - Vector of scopes from the incoming vector that are not
917c478bd9Sstevel@tonic-gate      * supported by any known DA.
927c478bd9Sstevel@tonic-gate      *
937c478bd9Sstevel@tonic-gate      * UNICAST_KEY - Vector of DATable.DARecord objects containing
947c478bd9Sstevel@tonic-gate      * equivalence classes of DAs that all support the same set of scopes.
957c478bd9Sstevel@tonic-gate      * Only DAs supporting one or more scopes in the incoming vector
967c478bd9Sstevel@tonic-gate      * are returned.
977c478bd9Sstevel@tonic-gate      *
987c478bd9Sstevel@tonic-gate      * Note that the equivalence classes don't necessarily mean that the
997c478bd9Sstevel@tonic-gate      * set of scopes are mutually exclusive. For example, if DA1 supports
1007c478bd9Sstevel@tonic-gate      * scopes A, B, and C; and DA2 supports scopes C and D, then they
1017c478bd9Sstevel@tonic-gate      * are in separate equivalence classes even though they both support
1027c478bd9Sstevel@tonic-gate      * C. But if DA2 supports A, B, and C; then it is in the same equivalence
1037c478bd9Sstevel@tonic-gate      * class.
1047c478bd9Sstevel@tonic-gate      *
1057c478bd9Sstevel@tonic-gate      * @param scopes The scopes for which DAs are required.
1067c478bd9Sstevel@tonic-gate      * @return A Hashtable with the multicast scopes and DAAddresses.
1077c478bd9Sstevel@tonic-gate      */
1087c478bd9Sstevel@tonic-gate 
findDAScopes(Vector scopes)1097c478bd9Sstevel@tonic-gate     abstract Hashtable findDAScopes(Vector scopes)
1107c478bd9Sstevel@tonic-gate 	throws ServiceLocationException;
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate     /**
1137c478bd9Sstevel@tonic-gate      * Remove a DA by address.
1147c478bd9Sstevel@tonic-gate      *
1157c478bd9Sstevel@tonic-gate      * @param address The host address of the DA.
1167c478bd9Sstevel@tonic-gate      * @param scopes The scopes.
1177c478bd9Sstevel@tonic-gate      * @return True if removed, false if not.
1187c478bd9Sstevel@tonic-gate      */
1197c478bd9Sstevel@tonic-gate 
removeDA(InetAddress address, Vector scopes)1207c478bd9Sstevel@tonic-gate     abstract boolean removeDA(InetAddress address, Vector scopes);
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate     /**
1237c478bd9Sstevel@tonic-gate      * Return a vector of scopes that the SA or UA client should use.
1247c478bd9Sstevel@tonic-gate      * Note that if no DAs are around, SA adverts must be used to
1257c478bd9Sstevel@tonic-gate      * find SAs. We must sort through the returned DAs and apply
1267c478bd9Sstevel@tonic-gate      * the scope prioritization algorithm to them.
1277c478bd9Sstevel@tonic-gate      *
1287c478bd9Sstevel@tonic-gate      * @return Vector of scopes for the SA or UA client to use.
1297c478bd9Sstevel@tonic-gate      */
1307c478bd9Sstevel@tonic-gate 
findScopes()1317c478bd9Sstevel@tonic-gate     synchronized Vector findScopes() throws ServiceLocationException {
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 	// First, get the DA addresses v.s. scopes table from the DAtable.
1347c478bd9Sstevel@tonic-gate 	//  This will also include DA addresses from the configuration file,
1357c478bd9Sstevel@tonic-gate 	//  if any. We don't filter on any scopes, since we want all of
1367c478bd9Sstevel@tonic-gate 	//  them. We are only interested in v2 scopes here.
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	Vector scopes = new Vector();
1397c478bd9Sstevel@tonic-gate 	Hashtable daRec = daTable.findDAScopes(scopes);
1407c478bd9Sstevel@tonic-gate 	Vector daEquivClasses = (Vector)daRec.get(UNICAST_KEY);
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	if (daEquivClasses != null) {
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 	    // Go through the equivalence classes and pull out scopes.
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	    int i, n = daEquivClasses.size();
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 	    for (i = 0; i < n; i++) {
1497c478bd9Sstevel@tonic-gate 		DARecord rec = (DARecord)daEquivClasses.elementAt(i);
1507c478bd9Sstevel@tonic-gate 		Vector v = rec.scopes;
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 		int j, m = v.size();
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 		for (j = 0; j < m; j++) {
1557c478bd9Sstevel@tonic-gate 		    Object s = v.elementAt(j);
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 		    // Unicast scopes take precedence over multicast scopes,
1587c478bd9Sstevel@tonic-gate 		    //  so insert them at the beginning of the vector.
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 		    if (!scopes.contains(s)) {
1617c478bd9Sstevel@tonic-gate 			scopes.addElement(s);
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 		    }
1647c478bd9Sstevel@tonic-gate 		}
1657c478bd9Sstevel@tonic-gate 	    }
1667c478bd9Sstevel@tonic-gate 	}
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	return scopes;
1697c478bd9Sstevel@tonic-gate     }
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate     /**
1727c478bd9Sstevel@tonic-gate      * Get the right DA table implementation. The property
1737c478bd9Sstevel@tonic-gate      * sun.net.slp.DATableClass determines the class.
1747c478bd9Sstevel@tonic-gate      *
1757c478bd9Sstevel@tonic-gate      * @return The DATable object for this process' SLP requests.
1767c478bd9Sstevel@tonic-gate      */
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 
getDATable()1797c478bd9Sstevel@tonic-gate     static DATable getDATable() {
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	// Return it right up front if we have it.
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	if (daTable != null) {
1847c478bd9Sstevel@tonic-gate 	    return daTable;
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	}
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 	conf = SLPConfig.getSLPConfig();
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	// Link and instantiate it.
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	daTable = linkAndInstantiateFromProp();
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	return daTable;
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate     }
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate     // Link and instantiate the class in the property.
1997c478bd9Sstevel@tonic-gate 
linkAndInstantiateFromProp()2007c478bd9Sstevel@tonic-gate     static protected DATable linkAndInstantiateFromProp() {
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	// Get the property.
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	String className = System.getProperty(DA_TABLE_CLASS_PROP);
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	if (className == null) {
2077c478bd9Sstevel@tonic-gate 	    Assert.slpassert(false,
2087c478bd9Sstevel@tonic-gate 			  "no_da_table",
2097c478bd9Sstevel@tonic-gate 			  new Object[] {DA_TABLE_CLASS_PROP});
2107c478bd9Sstevel@tonic-gate 	}
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	Class tclass = null;
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 	// Link the class and instantiate the object.
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	try {
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	    tclass = Class.forName(className);
2197c478bd9Sstevel@tonic-gate 	    daTable = (DATable)tclass.newInstance();
2207c478bd9Sstevel@tonic-gate 	    return daTable;
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	} catch (ClassNotFoundException ex) {
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	    Assert.slpassert(false,
2257c478bd9Sstevel@tonic-gate 			  "no_da_table_class",
2267c478bd9Sstevel@tonic-gate 			  new Object[] {className});
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	} catch (InstantiationException ex) {
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	    Assert.slpassert(false,
2317c478bd9Sstevel@tonic-gate 			  "instantiation_exception",
2327c478bd9Sstevel@tonic-gate 			  new Object[] {className});
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 	} catch (IllegalAccessException ex) {
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	    Assert.slpassert(false,
2377c478bd9Sstevel@tonic-gate 			  "access_exception",
2387c478bd9Sstevel@tonic-gate 			  new Object[] {className});
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	}
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 	// We won't reach this point, since the assertions will capture
2437c478bd9Sstevel@tonic-gate 	//  any errors and kill the program.
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	return null;
2467c478bd9Sstevel@tonic-gate     }
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate     //
2497c478bd9Sstevel@tonic-gate     // Utility functions for DA filtering and handling scopes.
2507c478bd9Sstevel@tonic-gate     //
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate     // Filter scopes, removing any not on the filter list if inVector is
2537c478bd9Sstevel@tonic-gate     //  false and removing any in the filter list if inVector is true.
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate     public static void
filterScopes(Vector scopes, Vector filter, boolean inVector)2567c478bd9Sstevel@tonic-gate 	filterScopes(Vector scopes, Vector filter, boolean inVector) {
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	int i = 0;
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	// Null or empty filter vector means that all should be accepted.
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	if (filter != null && !(filter.size() <= 0)) {
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 	    while (i < scopes.size()) {
2657c478bd9Sstevel@tonic-gate 		String scope = (String)scopes.elementAt(i);
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 		if ((!inVector && !filter.contains(scope)) ||
2687c478bd9Sstevel@tonic-gate 		    (inVector && filter.contains(scope))) {
2697c478bd9Sstevel@tonic-gate 		    scopes.removeElementAt(i);
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 		} else {
2727c478bd9Sstevel@tonic-gate 		    i++;
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 		}
2757c478bd9Sstevel@tonic-gate 	    }
2767c478bd9Sstevel@tonic-gate 	}
2777c478bd9Sstevel@tonic-gate     }
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate     // Add a new address to the equivalence class.
2807c478bd9Sstevel@tonic-gate 
addToEquivClass(String daaddr, Vector scopes, Vector ret)2817c478bd9Sstevel@tonic-gate     static boolean addToEquivClass(String daaddr, Vector scopes, Vector ret) {
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	// Create the InetAddress object.
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	InetAddress addr = null;
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	try {
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	    addr = InetAddress.getByName(daaddr);
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	} catch (UnknownHostException ex) {
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 	    if (conf.traceAll()) {
2947c478bd9Sstevel@tonic-gate 		conf.writeLog("unknown_da_address",
2957c478bd9Sstevel@tonic-gate 			      new Object[] {daaddr});
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	    }
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	    return false;
3007c478bd9Sstevel@tonic-gate 	}
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	// Go through the existing vector.
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	int i, n = ret.size();
3057c478bd9Sstevel@tonic-gate 	boolean equivalent = false;
3067c478bd9Sstevel@tonic-gate 	DARecord rec = null;
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate     outer: for (i = 0; i < n && equivalent == false; i++) {
3097c478bd9Sstevel@tonic-gate 	rec = (DARecord)ret.elementAt(i);
3107c478bd9Sstevel@tonic-gate 	Vector dascopes = rec.scopes;
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	int j, m = dascopes.size();
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	for (j = 0; j < m; j++) {
3157c478bd9Sstevel@tonic-gate 	    String scope = (String)dascopes.elementAt(j);
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	    if (!scopes.contains(scope)) {
3187c478bd9Sstevel@tonic-gate 		continue outer;
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	    }
3217c478bd9Sstevel@tonic-gate 	}
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 	equivalent = true;
3247c478bd9Sstevel@tonic-gate     }
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 	// Make a new record if not equivalent.
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	if (!equivalent) {
3297c478bd9Sstevel@tonic-gate 	    rec = new DATable.DARecord();
3307c478bd9Sstevel@tonic-gate 	    rec.scopes = (Vector)scopes.clone();
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	    ret.addElement(rec);
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	}
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	// Add to record. Optimize, by putting the local address at the
3387c478bd9Sstevel@tonic-gate 	//  beginning of the vector.
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	Vector interfaces = conf.getInterfaces();
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	if (interfaces.contains(addr)) {
3437c478bd9Sstevel@tonic-gate 	    rec.daAddresses.insertElementAt(addr, 0);
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	} else {
3467c478bd9Sstevel@tonic-gate 	    rec.daAddresses.addElement(addr);
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 	}
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	return true;
3517c478bd9Sstevel@tonic-gate     }
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate     /**
3547c478bd9Sstevel@tonic-gate      * Validate the scope names. We check that they are all strings,
3557c478bd9Sstevel@tonic-gate      * that none are the empty string. In addition, we collate to
3567c478bd9Sstevel@tonic-gate      * remove duplicates, and lower case.
3577c478bd9Sstevel@tonic-gate      */
3587c478bd9Sstevel@tonic-gate 
validateScopes(Vector scopes, Locale locale)3597c478bd9Sstevel@tonic-gate     static void validateScopes(Vector scopes, Locale locale)
3607c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	// Check for empty vector.
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	if (scopes == null || scopes.size() <= 0) {
3657c478bd9Sstevel@tonic-gate 	    throw
3667c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
3677c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
3687c478bd9Sstevel@tonic-gate 				"no_scope_vector",
3697c478bd9Sstevel@tonic-gate 				new Object[0]);
3707c478bd9Sstevel@tonic-gate 	}
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	// Check for all strings and none empty.
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	int i;
3757c478bd9Sstevel@tonic-gate 	Hashtable ht = new Hashtable();
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	for (i = 0; i < scopes.size(); i++) {
3787c478bd9Sstevel@tonic-gate 	    Object o = scopes.elementAt(i);
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	    if (!(o instanceof String)) {
3817c478bd9Sstevel@tonic-gate 		throw
3827c478bd9Sstevel@tonic-gate 		    new ServiceLocationException(
3837c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
3847c478bd9Sstevel@tonic-gate 				"non_string_element",
3857c478bd9Sstevel@tonic-gate 				new Object[] {scopes});
3867c478bd9Sstevel@tonic-gate 	    }
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	    String str = (String)o;
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 	    if (str.length() <= 0) {
3917c478bd9Sstevel@tonic-gate 		throw
3927c478bd9Sstevel@tonic-gate 		    new ServiceLocationException(
3937c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
3947c478bd9Sstevel@tonic-gate 				"null_element",
3957c478bd9Sstevel@tonic-gate 				new Object[] {scopes});
3967c478bd9Sstevel@tonic-gate 	    }
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 	    // Lower case, trim.
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	    str = str.toLowerCase(locale).trim();
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	    // Squeeze out spaces.
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	    StringBuffer buf = new StringBuffer();
4057c478bd9Sstevel@tonic-gate 	    StringTokenizer tk =
4067c478bd9Sstevel@tonic-gate 		new StringTokenizer(str, ServiceLocationAttribute.WHITESPACE);
4077c478bd9Sstevel@tonic-gate 	    String tok = null;
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	    while (tk.hasMoreTokens()) {
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 		// Add a single embedded whitespace for each group found.
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 		if (tok != null) {
4147c478bd9Sstevel@tonic-gate 		    buf.append(" ");
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 		}
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 		tok = tk.nextToken();
4197c478bd9Sstevel@tonic-gate 		buf.append(tok);
4207c478bd9Sstevel@tonic-gate 	    }
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	    str = buf.toString();
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 	    // If it wasn't already seen, put it into the hashtable.
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 	    if (ht.get(str) == null) {
4277c478bd9Sstevel@tonic-gate 		ht.put(str, str);
4287c478bd9Sstevel@tonic-gate 		scopes.setElementAt(str, i);
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	    } else {
4317c478bd9Sstevel@tonic-gate 		/*
4327c478bd9Sstevel@tonic-gate 		 *  Must decrement the index 'i' otherwise the next iteration
4337c478bd9Sstevel@tonic-gate 		 *  around the loop will miss the element immediately after
4347c478bd9Sstevel@tonic-gate 		 *  the element removed.
4357c478bd9Sstevel@tonic-gate 		 *
4367c478bd9Sstevel@tonic-gate 		 *  WARNING: Do not use 'i' again until the loop has
4377c478bd9Sstevel@tonic-gate 		 *           iterated as it may, after decrementing,
4387c478bd9Sstevel@tonic-gate 		 *           be negative.
4397c478bd9Sstevel@tonic-gate 		 */
4407c478bd9Sstevel@tonic-gate 		scopes.removeElementAt(i);
4417c478bd9Sstevel@tonic-gate 		i--;
4427c478bd9Sstevel@tonic-gate 		continue;
4437c478bd9Sstevel@tonic-gate 	    }
4447c478bd9Sstevel@tonic-gate 	}
4457c478bd9Sstevel@tonic-gate     }
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate }
448