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