/*
* 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) 2001 by Sun Microsystems, Inc.
* All rights reserved.
*
*/
// SunServerDATable.java: Server DA Table for Sun's client/SA server SLP.
// Author: James Kempf
// Created On: Wed May 20 09:58:46 1998
// Last Modified By: James Kempf
// Last Modified On: Mon Mar 8 14:30:29 1999
// Update Count: 79
//
package com.sun.slp;
import java.util.*;
import java.net.*;
import java.io.*;
/**
* SunServerDATable is a subclass class that provides the
* implementation for DA storage on Solaris. As described in
* the header for SunDATable, DA information is stored in the server's
* SA table as the service type "directory-agent.sun" with a
* attribute, scopes. The attribute contains a list of scopes supported
* by the DA. The service: URL of the registration contains the
* DA address as the host, followed by the list of scopes as an attribute
* in the URL part. An example is:
*
* service:directory-agent.sun:// 199.200.200.5/scopes=eng, corp, freeb
*
* The scopes of the registration are the scopes provided as the Sun-specific
* system property "sun.net.slp.SAOnlyScopes". By convention, this is
* initialized to be the local machine name, but it may also include other
* names.
*
* @author James Kempf
*/
class SunServerDATable extends ServerDATable {
// DA boot timestamp.
static final private String TIMESTAMP_ID =
"424242SUN-TABLE-TIMESTAMP424242";
// Address. Makes deletion easier.
static final private String ADDRESS_ID = "424242SUN-TABLE-ADDRESS424242";
private ServiceTable serviceTable = null; // SA table for regs.
private Vector saOnlyScopes = null; // Scopes for SA only.
SunServerDATable() {
// Get the service table.
try {
serviceTable = ServiceTable.getServiceTable();
} catch (ServiceLocationException ex) {
}
// Get the vector of SA scopes.
saOnlyScopes = conf.getSAOnlyScopes();
Assert.slpassert(saOnlyScopes.size() > 0,
"no_sa_scopes",
new Object[0]);
}
/**
* Record a new DA in the service table.
*
* @param URL The DAAdvert URL.
* @param scopes The scopes.
* @param version DA version number.
* @param spis SPIs this DA can support
* @return The boot timestamp in the previous registration. Used
* to determine if registration is necessary. If an error occurs,
* the returned value is negative. If the DA is new, the return
* value is the maximum long value. This will cause all
* registrations to be forwarded, because it is larger than any
* current time.
*/
public synchronized long
recordNewDA(ServiceURL url,
Vector scopes,
long timestamp,
int version,
Vector attrs,
String spis) {
String addr = url.getHost();
long formerTimestamp = -1L;
// We record all DAs regardless of whether we support them or not,
// because a UA client may be using the user selectable scoping
// model and therefore may want to see them.
Vector v = (Vector)scopes.clone();
// Add the Sun attributes.
ServiceLocationAttribute attr =
new ServiceLocationAttribute(SunDATable.SCOPES_ID, scopes);
attrs.addElement(attr);
Vector vals = new Vector();
vals.addElement(Long.toString(timestamp));
attr =
new ServiceLocationAttribute(SunServerDATable.TIMESTAMP_ID, vals);
attrs.addElement(attr);
vals = new Vector();
vals.addElement(new Integer(version));
attr = new ServiceLocationAttribute(SunDATable.VERSION_ID, vals);
attrs.addElement(attr);
vals = new Vector();
vals.addElement(url.getHost());
attr = new ServiceLocationAttribute(SunServerDATable.ADDRESS_ID, vals);
attrs.addElement(attr);
// Form the URL for the DA.
ServiceURL adURL = formServiceTableDAURL(url, attrs);
// Reach *around* the service table for registration, because
// we don't need a message. The service table abstraction
// is basically for decoding message objects, and we already
// have things in the internal form needed by the service store.
ServiceStore store = serviceTable.store;
try {
// First, get the boot time stamp if there.
Vector tags = new Vector();
tags.addElement(SunServerDATable.TIMESTAMP_ID);
Hashtable attrRec =
store.findAttributes(adURL,
saOnlyScopes,
tags,
Defaults.locale);
Vector formerAttrs =
(Vector)attrRec.get(ServiceStore.FA_ATTRIBUTES);
// If there, then get the old timestamp.
if (formerAttrs != null && !(formerAttrs.size() <= 0)) {
// Get the timestamp into a long.
attr = (ServiceLocationAttribute)formerAttrs.elementAt(0);
vals = attr.getValues();
String stamp = (String)vals.elementAt(0);
try {
formerTimestamp = Long.parseLong(stamp.trim());
} catch (NumberFormatException ex) {
Assert.slpassert(false,
"ssdat_number_format",
new Object[0]);
}
}
// Now register the URL.
store.register(adURL,
attrs,
saOnlyScopes,
Defaults.locale,
null,
null);
// Keep track of this DAs supported SPIs
LinkedList spiList =
AuthBlock.commaSeparatedListToLinkedList(spis);
// convert addr to an InetAddress for hashing
InetAddress inetAddr = null;
try {
inetAddr = InetAddress.getByName(addr);
} catch (UnknownHostException e) {}
// If we didn't get the InetAddress, this DA will never be used
// anyway
if (addr != null) {
daSPIsHash.put(inetAddr, spiList);
}
} catch (ServiceLocationException ex) {
conf.writeLog("ssdat_register_error",
new Object[] {
ex.getMessage(),
adURL,
saOnlyScopes});
}
return formerTimestamp;
}
/**
* Remove a DA. The Sun-specific convention is used to deregister
* the URL.
*
* @param address The host address of the DA, from its service URL.
* @param scopes The scopes.
* @return True if removed, false if not.
*/
public synchronized boolean removeDA(InetAddress address, Vector scopes) {
// Find URLs corresponding to this address.
String query = "(" + ADDRESS_ID + "=" + address.getHostAddress() + ")";
// Reach *around* the service table for dregistration, because
// we don't need a message. The service table abstraction
// is basically for decoding message objects, and we already
// have things in the internal form needed by the service store.
ServiceStore store = serviceTable.store;
try {
Hashtable das = returnMatchingDAs(query);
Enumeration daURLs = das.keys();
while (daURLs.hasMoreElements()) {
ServiceURL adURL = (ServiceURL)daURLs.nextElement();
store.deregister(adURL, saOnlyScopes, null);
}
} catch (ServiceLocationException ex) {
conf.writeLog("ssdat_deregister_error",
new Object[] {
ex.getMessage(),
address,
saOnlyScopes});
return false;
}
return true;
}
/**
* Return a hashtable in ServiceTable.findServices() format (e.g.
* URL's as keys, scopes as values) for DAs matching the query.
*
* @param query Query for DA attributes.
*/
public synchronized Hashtable returnMatchingDAs(String query)
throws ServiceLocationException {
ServiceStore store = ServiceTable.getServiceTable().store;
// Get DA records matching the query.
Vector saOnlyScopes = conf.getSAOnlyScopes();
Hashtable returns =
store.findServices(Defaults.SUN_DA_SERVICE_TYPE.toString(),
saOnlyScopes,
query,
Defaults.locale);
// Return the hashtable of services v.s. scopes.
return (Hashtable)returns.get(ServiceStore.FS_SERVICES);
}
/**
* Return a hashtable of DA equivalence classes and multicast
* scopes. Multicast scopes are stored in the special hashtable
* key MULTICAST_KEY. Unicast DA equivalence classes are stored
* under the key UNICAST_KEY. This implementation goes directly
* to the service table in the SA server for the DA addresses.
*
* @param scopes Scope list for DAs needed.
* @return Hashtable with DA addresses as keys and scopes to contact
* them with as values. Any scopes not associated with a
* DA come back stored under the key MULTICAST_KEY.
* Unicast DA equivalence classes are stored
* under the key UNICAST_KEY.
*/
public synchronized Hashtable findDAScopes(Vector scopes)
throws ServiceLocationException {
// Formulate a query for the DAs.
int i, n = scopes.size();
StringBuffer buf = new StringBuffer();
for (i = 0; i < n; i++) {
buf.append("(");
buf.append(SunDATable.SCOPES_ID);
buf.append("=");
buf.append((String)scopes.elementAt(i));
buf.append(")");
}
// Add logical disjunction if more than one element.
if (i > 1) {
buf.insert(0, "(|");
buf.append(")");
}
// Add version number.
if (i > 0) {
buf.insert(0, "(&");
}
buf.append("(");
buf.append(SunDATable.VERSION_ID);
buf.append("=");
buf.append((new Integer(Defaults.version)).toString());
buf.append(")");
// Add closing paren if there were any scopes.
if (i > 0) {
buf.append(")");
}
ServiceStore store = serviceTable.store;
Hashtable returns =
store.findServices(Defaults.SUN_DA_SERVICE_TYPE.toString(),
saOnlyScopes,
buf.toString(),
Defaults.locale);
Hashtable retRec = (Hashtable)returns.get(ServiceStore.FS_SERVICES);
// Convert to a vector. Keys are the service: URLs.
Enumeration en = retRec.keys();
Vector ret = new Vector();
Vector multiScopes = (Vector)scopes.clone();
Vector attrTags = new Vector();
attrTags.addElement(SunDATable.SCOPES_ID);
while (en.hasMoreElements()) {
ServiceURL url = (ServiceURL)en.nextElement();
Vector urlScopes = (Vector)retRec.get(url);
// Get the scope attributes for this URL.
Hashtable attrRec =
store.findAttributes(url,
urlScopes,
attrTags,
Defaults.locale);
Vector retAttrs = (Vector)attrRec.get(ServiceStore.FA_ATTRIBUTES);
String host = url.getHost();
Vector retScopes = null;
n = retAttrs.size();
for (i = 0; i < n; i++) {
ServiceLocationAttribute attr =
(ServiceLocationAttribute)retAttrs.elementAt(i);
// Distinguish based on type. We assume the attributes are
// prescreened when the URL was formed to make sure they're OK
String id = attr.getId();
Vector vals = attr.getValues();
if (id.equals(SunDATable.SCOPES_ID)) {
retScopes = vals;
}
}
// Add to equivalence class.
DATable.addToEquivClass(host, retScopes, ret);
// Filter scopes for any that might be multicast.
DATable.filterScopes(multiScopes, retScopes, false);
}
// Format the return.
retRec.clear();
if (multiScopes.size() > 0) {
retRec.put(DATable.MULTICAST_KEY, multiScopes);
}
if (ret.size() > 0) {
retRec.put(DATable.UNICAST_KEY, ret);
}
return retRec;
}
// Form a URL for the service table, from the DA URL and attributes.
// Attributes and scope have been prechecked for correctness.
private ServiceURL formServiceTableDAURL(ServiceURL url, Vector attrs) {
// Form up the URL part.
StringBuffer buf = new StringBuffer();
int i, n = attrs.size();
for (i = 0; i < n; i++) {
ServiceLocationAttribute attr =
(ServiceLocationAttribute)attrs.elementAt(i);
// If this is a URL attribute, then externalize and
// put into URL.
String id = attr.getId();
if (id.equals(SunDATable.SCOPES_ID)) {
String rep = "";
try {
rep = attr.externalize();
} catch (ServiceLocationException ex) {
conf.writeLog("ssdat_inter_attr_err",
new Object[] {attr, ex.getMessage()});
continue;
}
// Add semi if something already there.
if (buf.length() > 0) {
buf.append(";");
}
// Remove parens before inserting.
buf.append(rep.substring(1, rep.length()-1));
}
}
// Create the URL.
ServiceURL daURL =
new ServiceURL(Defaults.SUN_DA_SERVICE_TYPE+
"://"+
url.getHost()+
"/"+
buf.toString(),
url.getLifetime());
return daURL;
}
}