2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright 2001,2003 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A *
2N/A */
2N/A
2N/A// DATable.java: Interface for DATables.
2N/A// Author: James Kempf
2N/A// Created On: Mon May 11 13:46:02 1998
2N/A// Last Modified By: James Kempf
2N/A// Last Modified On: Mon Feb 22 15:47:37 1999
2N/A// Update Count: 53
2N/A//
2N/A
2N/A
2N/Apackage com.sun.slp;
2N/A
2N/A/**
2N/A * DATable is an abstract class that provides the interface for DA
2N/A * and scope discovery. A variety of implementations are possible.
2N/A * The getDATable() method creates the right one from a subclass.
2N/A *
2N/A * @author James Kempf
2N/A */
2N/A
2N/Aimport java.util.*;
2N/Aimport java.net.*;
2N/A
2N/Aabstract class DATable extends Object {
2N/A
2N/A protected static DATable daTable;
2N/A protected static SLPConfig conf;
2N/A
2N/A // System property naming the DATable implementation class to use.
2N/A
2N/A final static String DA_TABLE_CLASS_PROP = "sun.net.slp.DATableClass";
2N/A
2N/A // SA only scopes property.
2N/A
2N/A final static String SA_ONLY_SCOPES_PROP = "sun.net.slp.SAOnlyScopes";
2N/A
2N/A // Hashtable key for multicast scopes.
2N/A
2N/A final static String MULTICAST_KEY = "&&**^^MULTICASTxxxKEY^^**&&";
2N/A
2N/A // Hashtable key for DA equivalence classes.
2N/A
2N/A final static String UNICAST_KEY = "&&**^^UNICASTxxxKEY^^**&&";
2N/A
2N/A /**
2N/A * A record for all DAs supporting exactly the same set of scopes.
2N/A *
2N/A * @author James Kempf
2N/A */
2N/A
2N/A
2N/A public static class DARecord extends Object {
2N/A
2N/A // The scopes supported.
2N/A
2N/A Vector scopes = null; // String scope names
2N/A
2N/A Vector daAddresses = new Vector(); // InetAddress DA addresses
2N/A
2N/A }
2N/A
2N/A /**
2N/A * Return a hashtable containing two entries:
2N/A *
2N/A * MULTICAST_KEY - Vector of scopes from the incoming vector that are not
2N/A * supported by any known DA.
2N/A *
2N/A * UNICAST_KEY - Vector of DATable.DARecord objects containing
2N/A * equivalence classes of DAs that all support the same set of scopes.
2N/A * Only DAs supporting one or more scopes in the incoming vector
2N/A * are returned.
2N/A *
2N/A * Note that the equivalence classes don't necessarily mean that the
2N/A * set of scopes are mutually exclusive. For example, if DA1 supports
2N/A * scopes A, B, and C; and DA2 supports scopes C and D, then they
2N/A * are in separate equivalence classes even though they both support
2N/A * C. But if DA2 supports A, B, and C; then it is in the same equivalence
2N/A * class.
2N/A *
2N/A * @param scopes The scopes for which DAs are required.
2N/A * @return A Hashtable with the multicast scopes and DAAddresses.
2N/A */
2N/A
2N/A abstract Hashtable findDAScopes(Vector scopes)
2N/A throws ServiceLocationException;
2N/A
2N/A /**
2N/A * Remove a DA by address.
2N/A *
2N/A * @param address The host address of the DA.
2N/A * @param scopes The scopes.
2N/A * @return True if removed, false if not.
2N/A */
2N/A
2N/A abstract boolean removeDA(InetAddress address, Vector scopes);
2N/A
2N/A /**
2N/A * Return a vector of scopes that the SA or UA client should use.
2N/A * Note that if no DAs are around, SA adverts must be used to
2N/A * find SAs. We must sort through the returned DAs and apply
2N/A * the scope prioritization algorithm to them.
2N/A *
2N/A * @return Vector of scopes for the SA or UA client to use.
2N/A */
2N/A
2N/A synchronized Vector findScopes() throws ServiceLocationException {
2N/A
2N/A // First, get the DA addresses v.s. scopes table from the DAtable.
2N/A // This will also include DA addresses from the configuration file,
2N/A // if any. We don't filter on any scopes, since we want all of
2N/A // them. We are only interested in v2 scopes here.
2N/A
2N/A Vector scopes = new Vector();
2N/A Hashtable daRec = daTable.findDAScopes(scopes);
2N/A Vector daEquivClasses = (Vector)daRec.get(UNICAST_KEY);
2N/A
2N/A if (daEquivClasses != null) {
2N/A
2N/A // Go through the equivalence classes and pull out scopes.
2N/A
2N/A int i, n = daEquivClasses.size();
2N/A
2N/A for (i = 0; i < n; i++) {
2N/A DARecord rec = (DARecord)daEquivClasses.elementAt(i);
2N/A Vector v = rec.scopes;
2N/A
2N/A int j, m = v.size();
2N/A
2N/A for (j = 0; j < m; j++) {
2N/A Object s = v.elementAt(j);
2N/A
2N/A // Unicast scopes take precedence over multicast scopes,
2N/A // so insert them at the beginning of the vector.
2N/A
2N/A if (!scopes.contains(s)) {
2N/A scopes.addElement(s);
2N/A
2N/A }
2N/A }
2N/A }
2N/A }
2N/A
2N/A return scopes;
2N/A }
2N/A
2N/A /**
2N/A * Get the right DA table implementation. The property
2N/A * sun.net.slp.DATableClass determines the class.
2N/A *
2N/A * @return The DATable object for this process' SLP requests.
2N/A */
2N/A
2N/A
2N/A static DATable getDATable() {
2N/A
2N/A // Return it right up front if we have it.
2N/A
2N/A if (daTable != null) {
2N/A return daTable;
2N/A
2N/A }
2N/A
2N/A conf = SLPConfig.getSLPConfig();
2N/A
2N/A // Link and instantiate it.
2N/A
2N/A daTable = linkAndInstantiateFromProp();
2N/A
2N/A return daTable;
2N/A
2N/A }
2N/A
2N/A // Link and instantiate the class in the property.
2N/A
2N/A static protected DATable linkAndInstantiateFromProp() {
2N/A
2N/A // Get the property.
2N/A
2N/A String className = System.getProperty(DA_TABLE_CLASS_PROP);
2N/A
2N/A if (className == null) {
2N/A Assert.slpassert(false,
2N/A "no_da_table",
2N/A new Object[] {DA_TABLE_CLASS_PROP});
2N/A }
2N/A
2N/A Class tclass = null;
2N/A
2N/A // Link the class and instantiate the object.
2N/A
2N/A try {
2N/A
2N/A tclass = Class.forName(className);
2N/A daTable = (DATable)tclass.newInstance();
2N/A return daTable;
2N/A
2N/A } catch (ClassNotFoundException ex) {
2N/A
2N/A Assert.slpassert(false,
2N/A "no_da_table_class",
2N/A new Object[] {className});
2N/A
2N/A } catch (InstantiationException ex) {
2N/A
2N/A Assert.slpassert(false,
2N/A "instantiation_exception",
2N/A new Object[] {className});
2N/A
2N/A } catch (IllegalAccessException ex) {
2N/A
2N/A Assert.slpassert(false,
2N/A "access_exception",
2N/A new Object[] {className});
2N/A
2N/A }
2N/A
2N/A // We won't reach this point, since the assertions will capture
2N/A // any errors and kill the program.
2N/A
2N/A return null;
2N/A }
2N/A
2N/A //
2N/A // Utility functions for DA filtering and handling scopes.
2N/A //
2N/A
2N/A // Filter scopes, removing any not on the filter list if inVector is
2N/A // false and removing any in the filter list if inVector is true.
2N/A
2N/A public static void
2N/A filterScopes(Vector scopes, Vector filter, boolean inVector) {
2N/A
2N/A int i = 0;
2N/A
2N/A // Null or empty filter vector means that all should be accepted.
2N/A
2N/A if (filter != null && !(filter.size() <= 0)) {
2N/A
2N/A while (i < scopes.size()) {
2N/A String scope = (String)scopes.elementAt(i);
2N/A
2N/A if ((!inVector && !filter.contains(scope)) ||
2N/A (inVector && filter.contains(scope))) {
2N/A scopes.removeElementAt(i);
2N/A
2N/A } else {
2N/A i++;
2N/A
2N/A }
2N/A }
2N/A }
2N/A }
2N/A
2N/A // Add a new address to the equivalence class.
2N/A
2N/A static boolean addToEquivClass(String daaddr, Vector scopes, Vector ret) {
2N/A
2N/A // Create the InetAddress object.
2N/A
2N/A InetAddress addr = null;
2N/A
2N/A try {
2N/A
2N/A addr = InetAddress.getByName(daaddr);
2N/A
2N/A } catch (UnknownHostException ex) {
2N/A
2N/A if (conf.traceAll()) {
2N/A conf.writeLog("unknown_da_address",
2N/A new Object[] {daaddr});
2N/A
2N/A }
2N/A
2N/A return false;
2N/A }
2N/A
2N/A // Go through the existing vector.
2N/A
2N/A int i, n = ret.size();
2N/A boolean equivalent = false;
2N/A DARecord rec = null;
2N/A
2N/A outer: for (i = 0; i < n && equivalent == false; i++) {
2N/A rec = (DARecord)ret.elementAt(i);
2N/A Vector dascopes = rec.scopes;
2N/A
2N/A int j, m = dascopes.size();
2N/A
2N/A for (j = 0; j < m; j++) {
2N/A String scope = (String)dascopes.elementAt(j);
2N/A
2N/A if (!scopes.contains(scope)) {
2N/A continue outer;
2N/A
2N/A }
2N/A }
2N/A
2N/A equivalent = true;
2N/A }
2N/A
2N/A // Make a new record if not equivalent.
2N/A
2N/A if (!equivalent) {
2N/A rec = new DATable.DARecord();
2N/A rec.scopes = (Vector)scopes.clone();
2N/A
2N/A ret.addElement(rec);
2N/A
2N/A }
2N/A
2N/A
2N/A // Add to record. Optimize, by putting the local address at the
2N/A // beginning of the vector.
2N/A
2N/A Vector interfaces = conf.getInterfaces();
2N/A
2N/A if (interfaces.contains(addr)) {
2N/A rec.daAddresses.insertElementAt(addr, 0);
2N/A
2N/A } else {
2N/A rec.daAddresses.addElement(addr);
2N/A
2N/A }
2N/A
2N/A return true;
2N/A }
2N/A
2N/A /**
2N/A * Validate the scope names. We check that they are all strings,
2N/A * that none are the empty string. In addition, we collate to
2N/A * remove duplicates, and lower case.
2N/A */
2N/A
2N/A static void validateScopes(Vector scopes, Locale locale)
2N/A throws ServiceLocationException {
2N/A
2N/A // Check for empty vector.
2N/A
2N/A if (scopes == null || scopes.size() <= 0) {
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "no_scope_vector",
2N/A new Object[0]);
2N/A }
2N/A
2N/A // Check for all strings and none empty.
2N/A
2N/A int i;
2N/A Hashtable ht = new Hashtable();
2N/A
2N/A for (i = 0; i < scopes.size(); i++) {
2N/A Object o = scopes.elementAt(i);
2N/A
2N/A if (!(o instanceof String)) {
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "non_string_element",
2N/A new Object[] {scopes});
2N/A }
2N/A
2N/A String str = (String)o;
2N/A
2N/A if (str.length() <= 0) {
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "null_element",
2N/A new Object[] {scopes});
2N/A }
2N/A
2N/A // Lower case, trim.
2N/A
2N/A str = str.toLowerCase(locale).trim();
2N/A
2N/A // Squeeze out spaces.
2N/A
2N/A StringBuffer buf = new StringBuffer();
2N/A StringTokenizer tk =
2N/A new StringTokenizer(str, ServiceLocationAttribute.WHITESPACE);
2N/A String tok = null;
2N/A
2N/A while (tk.hasMoreTokens()) {
2N/A
2N/A // Add a single embedded whitespace for each group found.
2N/A
2N/A if (tok != null) {
2N/A buf.append(" ");
2N/A
2N/A }
2N/A
2N/A tok = tk.nextToken();
2N/A buf.append(tok);
2N/A }
2N/A
2N/A str = buf.toString();
2N/A
2N/A // If it wasn't already seen, put it into the hashtable.
2N/A
2N/A if (ht.get(str) == null) {
2N/A ht.put(str, str);
2N/A scopes.setElementAt(str, i);
2N/A
2N/A } else {
2N/A /*
2N/A * Must decrement the index 'i' otherwise the next iteration
2N/A * around the loop will miss the element immediately after
2N/A * the element removed.
2N/A *
2N/A * WARNING: Do not use 'i' again until the loop has
2N/A * iterated as it may, after decrementing,
2N/A * be negative.
2N/A */
2N/A scopes.removeElementAt(i);
2N/A i--;
2N/A continue;
2N/A }
2N/A }
2N/A }
2N/A
2N/A}