xref: /onnv-gate/usr/src/lib/libslp/javalib/com/sun/slp/ServiceTable.java (revision 7298:b69e27387f74)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7298SMark.J.Nelson@Sun.COM  * Common Development and Distribution License (the "License").
6*7298SMark.J.Nelson@Sun.COM  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
220Sstevel@tonic-gate  * Copyright (c) 1999 by Sun Microsystems, Inc.
230Sstevel@tonic-gate  * All rights reserved.
240Sstevel@tonic-gate  *
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate //  ServiceTable.java: Storage of all services.
280Sstevel@tonic-gate //  Author:           James Kempf
290Sstevel@tonic-gate //  Created On:       Fri Oct 10 14:23:25 1997
300Sstevel@tonic-gate //  Last Modified By: James Kempf
310Sstevel@tonic-gate //  Last Modified On: Thu Apr  1 10:33:46 1999
320Sstevel@tonic-gate //  Update Count:     461
330Sstevel@tonic-gate //
340Sstevel@tonic-gate 
350Sstevel@tonic-gate package com.sun.slp;
360Sstevel@tonic-gate 
370Sstevel@tonic-gate import java.util.*;
380Sstevel@tonic-gate import java.io.*;
390Sstevel@tonic-gate import java.security.*;
400Sstevel@tonic-gate import java.net.*;
410Sstevel@tonic-gate 
420Sstevel@tonic-gate /**
430Sstevel@tonic-gate  * The ServiceTable object records all service registrations. Note
440Sstevel@tonic-gate  * that any exceptions internal to the service table are processed
450Sstevel@tonic-gate  * and either returned as SrvRply objects or are reported.
460Sstevel@tonic-gate  *
470Sstevel@tonic-gate  * @author James Kempf
480Sstevel@tonic-gate  */
490Sstevel@tonic-gate 
500Sstevel@tonic-gate class ServiceTable extends Object {
510Sstevel@tonic-gate 
520Sstevel@tonic-gate     // Key for SDAAdvert class.
530Sstevel@tonic-gate 
540Sstevel@tonic-gate     static final String SDAADVERT = "com.sun.slp.SDAAdvert";
550Sstevel@tonic-gate 
560Sstevel@tonic-gate     private static final String locationMsg = "Service table";
570Sstevel@tonic-gate 
580Sstevel@tonic-gate     //
590Sstevel@tonic-gate     // Instance variables.
600Sstevel@tonic-gate     //
610Sstevel@tonic-gate 
620Sstevel@tonic-gate     // The service store.
630Sstevel@tonic-gate 
640Sstevel@tonic-gate     protected ServiceStore store = null;
650Sstevel@tonic-gate 
660Sstevel@tonic-gate     //
670Sstevel@tonic-gate     // Class variables.
680Sstevel@tonic-gate 
690Sstevel@tonic-gate     // System properties.
700Sstevel@tonic-gate 
710Sstevel@tonic-gate     static protected SLPConfig conf = null;
720Sstevel@tonic-gate 
730Sstevel@tonic-gate     // Singleton objects for the service tables.
740Sstevel@tonic-gate 
750Sstevel@tonic-gate     static protected ServiceTable table = null;
760Sstevel@tonic-gate 
770Sstevel@tonic-gate     // The ager thread.
780Sstevel@tonic-gate 
790Sstevel@tonic-gate     static protected AgerThread thrAger = null;
800Sstevel@tonic-gate 
810Sstevel@tonic-gate     // Time to sleep. Adjusted depending on incoming URLs.
820Sstevel@tonic-gate 
830Sstevel@tonic-gate     private static long sleepyTime = Defaults.lMaxSleepTime;
840Sstevel@tonic-gate 
850Sstevel@tonic-gate     //
860Sstevel@tonic-gate     // Creation of singleton.
870Sstevel@tonic-gate     //
880Sstevel@tonic-gate 
890Sstevel@tonic-gate     // Protected constructor.
900Sstevel@tonic-gate 
ServiceTable()910Sstevel@tonic-gate     protected ServiceTable() {
920Sstevel@tonic-gate 
930Sstevel@tonic-gate 	if (thrAger != null) {
940Sstevel@tonic-gate 	    return;
950Sstevel@tonic-gate 
960Sstevel@tonic-gate 	}
970Sstevel@tonic-gate 
980Sstevel@tonic-gate 	// Create the ager thread.
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate 	thrAger = new AgerThread();
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate 	// Set the priority low, so other things (like active discovery)
1030Sstevel@tonic-gate 	//  take priority.
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate 	thrAger.setPriority(Thread.MIN_PRIORITY);
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate 	thrAger.start();
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate     }
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate     /**
1120Sstevel@tonic-gate      * Return an SA service store.
1130Sstevel@tonic-gate      *
1140Sstevel@tonic-gate      * @return The distinguished table object.
1150Sstevel@tonic-gate      */
1160Sstevel@tonic-gate 
getServiceTable()1170Sstevel@tonic-gate     static ServiceTable getServiceTable()
1180Sstevel@tonic-gate 	throws ServiceLocationException {
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 	if (conf == null) {
1210Sstevel@tonic-gate 	    conf = SLPConfig.getSLPConfig();
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 	}
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate 	if (table == null) {
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate 	    table = createServiceTable();
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 	}
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate 	return table;
1320Sstevel@tonic-gate     }
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate     /**
1350Sstevel@tonic-gate      * Return a service table object.
1360Sstevel@tonic-gate      *
1370Sstevel@tonic-gate      * @return The service table object.
1380Sstevel@tonic-gate      */
1390Sstevel@tonic-gate 
createServiceTable()1400Sstevel@tonic-gate     private static ServiceTable createServiceTable()
1410Sstevel@tonic-gate 	throws ServiceLocationException {
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 	ServiceTable table = new ServiceTable();
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 	table.store = ServiceStoreFactory.createServiceStore();
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	return table;
1480Sstevel@tonic-gate     }
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate     //
1510Sstevel@tonic-gate     // Support for serializated registrations.
1520Sstevel@tonic-gate     //
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate     /**
1550Sstevel@tonic-gate      * If any serialized registrations are pending, then unserialize
1560Sstevel@tonic-gate      * and register.
1570Sstevel@tonic-gate      */
1580Sstevel@tonic-gate 
deserializeTable()1590Sstevel@tonic-gate     public void deserializeTable() {
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 	// If there are any serialized registrations, then get
1620Sstevel@tonic-gate 	//  them and perform registrations.
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 	String serializedURL = conf.getSerializedRegURL();
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 	if (serializedURL != null) {
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 	    ServiceStore serStore = getStoreFromURL(serializedURL);
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 	    if (serStore != null) {
1710Sstevel@tonic-gate 		registerStore(serStore);
1720Sstevel@tonic-gate 	    }
1730Sstevel@tonic-gate 	}
1740Sstevel@tonic-gate     }
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate     /**
1770Sstevel@tonic-gate      * Serialize the table to the URL.
1780Sstevel@tonic-gate      *
1790Sstevel@tonic-gate      * @param URL String giving the URL to which the store should be
1800Sstevel@tonic-gate      * serialized.
1810Sstevel@tonic-gate      */
1820Sstevel@tonic-gate 
serializeServiceStore(String URL)1830Sstevel@tonic-gate     void serializeServiceStore(String URL) {
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate 	// Open an object output stream for the URL, serialize through
1860Sstevel@tonic-gate 	//  the factory.
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate 	try {
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate 	    URL url = new URL(URL);
1910Sstevel@tonic-gate 	    URLConnection urlConn = url.openConnection();
1920Sstevel@tonic-gate 	    OutputStream os = urlConn.getOutputStream();
1930Sstevel@tonic-gate 	    BufferedWriter di =
1940Sstevel@tonic-gate 		new BufferedWriter(new OutputStreamWriter(os));
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate 	    // Serialize the store.
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 	    ServiceStoreFactory.serialize(di, store);
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	} catch (MalformedURLException ex) {
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate 	    conf.writeLog("st_serialized_malform",
2030Sstevel@tonic-gate 			  new Object[] {URL});
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 	} catch (UnsupportedEncodingException ex) {
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 	    conf.writeLog("st_unsupported_encoding",
2080Sstevel@tonic-gate 			  new Object[] {URL});
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	} catch (IOException ex) {
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	    conf.writeLog("st_serialized_ioexception",
2130Sstevel@tonic-gate 			  new Object[] {URL, ex});
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	} catch (ServiceLocationException ex) {
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 	    conf.writeLog("st_serialized_sle",
2180Sstevel@tonic-gate 			  new Object[] {URL, ex.getMessage()});
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	}
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate     }
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate     // Read proxy registrations from the URL.
2250Sstevel@tonic-gate 
getStoreFromURL(String serializedURL)2260Sstevel@tonic-gate     private ServiceStore getStoreFromURL(String serializedURL) {
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 	ServiceStore serStore = null;
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	// Open an object input stream for the URL, deserialize through
2310Sstevel@tonic-gate 	//  the factory.
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 	try {
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	    URL url = new URL(serializedURL);
2360Sstevel@tonic-gate 	    InputStream is = url.openStream();
2370Sstevel@tonic-gate 	    BufferedReader di = new BufferedReader(new InputStreamReader(is));
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 	    // Deserialize the objects.
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 	    serStore =
2420Sstevel@tonic-gate 		ServiceStoreFactory.deserializeServiceStore(di);
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 	} catch (MalformedURLException ex) {
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	    conf.writeLog("st_serialized_malform",
2470Sstevel@tonic-gate 			  new Object[] {serializedURL});
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 	} catch (UnsupportedEncodingException ex) {
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 	    conf.writeLog("st_unsupported_encoding",
2520Sstevel@tonic-gate 			  new Object[] {serializedURL});
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 	} catch (IOException ex) {
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 	    conf.writeLog("st_serialized_ioexception",
2570Sstevel@tonic-gate 			  new Object[] {
2580Sstevel@tonic-gate 		serializedURL,
2590Sstevel@tonic-gate 		    ex.getMessage()});
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	} catch (ServiceLocationException ex) {
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 	    conf.writeLog("st_serialized_sle",
2640Sstevel@tonic-gate 			  new Object[] {
2650Sstevel@tonic-gate 		serializedURL,
2660Sstevel@tonic-gate 		    ex.getMessage()});
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 	}
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 	return serStore;
2710Sstevel@tonic-gate     }
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate     // Walk the table, performing actual registrations on all records.
2740Sstevel@tonic-gate 
registerStore(ServiceStore serStore)2750Sstevel@tonic-gate     private void registerStore(ServiceStore serStore) {
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	// Walk the table.
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 	Enumeration en = serStore.getServiceRecordsByScope(null);
2800Sstevel@tonic-gate 	boolean hasURLSig = conf.getHasSecurity();
2810Sstevel@tonic-gate 	boolean hasAttrSig = conf.getHasSecurity();
2820Sstevel@tonic-gate 	PermSARegTable pregTable = 	SARequester.getPermSARegTable();
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 	while (en.hasMoreElements()) {
2850Sstevel@tonic-gate 	    ServiceStore.ServiceRecord rec =
2860Sstevel@tonic-gate 		(ServiceStore.ServiceRecord)en.nextElement();
2870Sstevel@tonic-gate 	    ServiceURL surl = rec.getServiceURL();
2880Sstevel@tonic-gate 	    Vector scopes = rec.getScopes();
2890Sstevel@tonic-gate 	    Vector attrs = rec.getAttrList();
2900Sstevel@tonic-gate 	    Locale locale = rec.getLocale();
2910Sstevel@tonic-gate 	    Hashtable urlSig = null;
2920Sstevel@tonic-gate 	    Hashtable attrSig = null;
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	    // Note that we can't use the Advertiser to register here,
2950Sstevel@tonic-gate 	    //  because we may not be listening yet for registrations.
2960Sstevel@tonic-gate 	    //  We need to do this all by hand.
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	    try {
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 		// Create a registration message for refreshing.
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 		CSrvReg creg = new CSrvReg(false,
3030Sstevel@tonic-gate 					   locale,
3040Sstevel@tonic-gate 					   surl,
3050Sstevel@tonic-gate 					   scopes,
3060Sstevel@tonic-gate 					   attrs,
3070Sstevel@tonic-gate 					   null,
3080Sstevel@tonic-gate 					   null);
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 		// We externalize to a server side message if authentication
3110Sstevel@tonic-gate 		//  is needed. This creates the auth blocks for the scopes.
3120Sstevel@tonic-gate 		//  Doing this in any other way is alot more complicated,
3130Sstevel@tonic-gate 		//  although doing it this way seems kludgy.
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 		if (hasURLSig || hasAttrSig) {
3160Sstevel@tonic-gate 		    ByteArrayOutputStream baos = new ByteArrayOutputStream();
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 		    creg.getHeader().externalize(baos, false, true);
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 		    ByteArrayInputStream bais =
3210Sstevel@tonic-gate 			new ByteArrayInputStream(baos.toByteArray());
3220Sstevel@tonic-gate 		    bais.read();	// pop off version and function code...
3230Sstevel@tonic-gate 		    bais.read();
3240Sstevel@tonic-gate 		    DataInputStream dis = new DataInputStream(bais);
3250Sstevel@tonic-gate 		    SLPHeaderV2 hdr = new SLPHeaderV2();
3260Sstevel@tonic-gate 		    hdr.parseHeader(SrvLocHeader.SrvReg, dis);
3270Sstevel@tonic-gate 		    SSrvReg sreg = new SSrvReg(hdr, dis);
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 		    // Now we've got it, after much effort. Get the auths.
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate 		    urlSig = sreg.URLSignature;
3320Sstevel@tonic-gate 		    attrSig = sreg.attrSignature;
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 		}
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 		store.register(surl, attrs, scopes, locale, urlSig, attrSig);
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 		// Now we've got to put the registration into the
3390Sstevel@tonic-gate 		//  PermSARegTable. Again, we do everything by hand
3400Sstevel@tonic-gate 		//  because we can't use Advertiser.
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 		if (surl.getIsPermanent()) {
3430Sstevel@tonic-gate 		    pregTable.reg(surl, creg);
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 		}
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 		// Report registration.
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 		if (conf.regTest()) {
3500Sstevel@tonic-gate 		    conf.writeLog("st_reg_add",
3510Sstevel@tonic-gate 				  new Object[] {
3520Sstevel@tonic-gate 			locationMsg,
3530Sstevel@tonic-gate 			    locale,
3540Sstevel@tonic-gate 			    surl.getServiceType(),
3550Sstevel@tonic-gate 			    surl,
3560Sstevel@tonic-gate 			    attrs,
3570Sstevel@tonic-gate 			    scopes});
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 		}
3600Sstevel@tonic-gate 	    } catch (ServiceLocationException ex) {
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 		String msg = ex.getMessage();
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 		conf.writeLog("st_serialized_seex",
3650Sstevel@tonic-gate 			      new Object[] {
3660Sstevel@tonic-gate 		    new Integer(ex.getErrorCode()),
3670Sstevel@tonic-gate 			surl,
3680Sstevel@tonic-gate 			(msg == null ? "<no message>":msg)});
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 	    } catch (Exception ex) {
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 		String msg = ex.getMessage();
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 		conf.writeLog("st_serialized_seex",
3750Sstevel@tonic-gate 			      new Object[] {
3760Sstevel@tonic-gate 		    surl,
3770Sstevel@tonic-gate 			(msg == null ? "<no message>":msg)});
3780Sstevel@tonic-gate 	    }
3790Sstevel@tonic-gate 	}
3800Sstevel@tonic-gate     }
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate     //
3830Sstevel@tonic-gate     // Record aging.
3840Sstevel@tonic-gate     //
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate     //
3870Sstevel@tonic-gate     // Run the thread that ages out records.
3880Sstevel@tonic-gate     //
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate     private class AgerThread extends Thread {
3910Sstevel@tonic-gate 
run()3920Sstevel@tonic-gate 	public void run() {
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	    setName("SLP Service Table Age-out");
3950Sstevel@tonic-gate 	    long alarmTime = sleepyTime;  // when to wake up next
3960Sstevel@tonic-gate 	    long wentToSleep = 0;	    // what time we went to bed
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 	    while (true) {
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 		try {
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 		    // Record when we went to sleep.
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 		    wentToSleep = System.currentTimeMillis();
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 		    // Sleep for the minimum amount of time needed before we
4070Sstevel@tonic-gate 		    //  must wake up and check.
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 		    sleep(alarmTime);
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 		} catch (InterruptedException ie) {
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 		    // A new registration came in. Calculate how much time
4140Sstevel@tonic-gate 		    //  remains until we would have woken up. If this is
4150Sstevel@tonic-gate 		    //  less than the new sleepyTime, then we set the alarm
4160Sstevel@tonic-gate 		    //  for this time. If it is more, then we set the alarm
4170Sstevel@tonic-gate 		    //  for the new sleepyTime.
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 		    long remainingSleepTime =
4200Sstevel@tonic-gate 			(wentToSleep + alarmTime) - System.currentTimeMillis();
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 		    remainingSleepTime =		// just in case...
4230Sstevel@tonic-gate 			((remainingSleepTime <= 0) ? 0 : remainingSleepTime);
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 		    alarmTime = sleepyTime;
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 		    if (remainingSleepTime < alarmTime) {
4280Sstevel@tonic-gate 			alarmTime = remainingSleepTime;
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 		    }
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 		    continue;  // we don't have to walk yet...
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 		}
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 		// Walk the table, get the new alarm and sleepy times.
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 		if (table != null) {
4390Sstevel@tonic-gate 		    table.ageStore();
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 		    alarmTime = sleepyTime;
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 		}
4440Sstevel@tonic-gate 	    }
4450Sstevel@tonic-gate 	}
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate     }
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate     /**
4500Sstevel@tonic-gate      * Age the service store.
4510Sstevel@tonic-gate      */
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate     // this method cannot be private... due to compiler weakness
ageStore()4540Sstevel@tonic-gate     void ageStore() {
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 	try {
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	    // We synchronize in case somebody registers and tries to
4590Sstevel@tonic-gate 	    //  change sleepy time.
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate 	    synchronized (store) {
4620Sstevel@tonic-gate 		Vector deleted = new Vector();
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate 		sleepyTime = store.ageOut(deleted);
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 		// Track unregistered services.
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 		int i, n = deleted.size();
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 		for (i = 0; i < n; i++) {
4710Sstevel@tonic-gate 		    ServiceStore.ServiceRecord rec =
4720Sstevel@tonic-gate 			(ServiceStore.ServiceRecord)deleted.elementAt(i);
4730Sstevel@tonic-gate 		    ServiceURL surl = rec.getServiceURL();
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 		    trackRegisteredServiceTypes(); // it's deleted...
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate 		}
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 	    }
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	} catch (RuntimeException ex) {
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 	    reportNonfatalException(ex, new Vector(), store);
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	} catch (ServiceLocationException ex) {
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 	    reportNonfatalException(ex, new Vector(), store);
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate 	}
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate     }
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate     //
4940Sstevel@tonic-gate     // SLP Service Table operations (register, deregister, etc.)
4950Sstevel@tonic-gate     //
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate     /**
4980Sstevel@tonic-gate      * Process the registration and record if no errors found.
4990Sstevel@tonic-gate      *
5000Sstevel@tonic-gate      * @param req Service registration request message.
5010Sstevel@tonic-gate      * @return SrvLocMsg A service registration acknowledgement.
5020Sstevel@tonic-gate      */
5030Sstevel@tonic-gate 
register(SSrvReg req)5040Sstevel@tonic-gate     SrvLocMsg register(SSrvReg req) {
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 	SrvLocHeader hdr = req.getHeader();
5070Sstevel@tonic-gate 	Locale locale = hdr.locale;
5080Sstevel@tonic-gate 	boolean fresh = hdr.fresh;
5090Sstevel@tonic-gate 	Vector scopes = hdr.scopes;
5100Sstevel@tonic-gate 	ServiceURL surl = req.URL;
5110Sstevel@tonic-gate 	String serviceType = req.serviceType;
5120Sstevel@tonic-gate 	Vector attrList = req.attrList;
5130Sstevel@tonic-gate 	Hashtable urlSig = req.URLSignature;
5140Sstevel@tonic-gate 	Hashtable attrSig = req.attrSignature;
5150Sstevel@tonic-gate 	short errorCode =
5160Sstevel@tonic-gate 	    (fresh ? ServiceLocationException.INVALID_REGISTRATION :
5170Sstevel@tonic-gate 	    ServiceLocationException.INVALID_UPDATE);
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 	try {
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	    // If a sig block came in, verify it.
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 	    if (urlSig != null) {
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 		AuthBlock.verifyAll(urlSig);
5260Sstevel@tonic-gate 	    }
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	    if (attrSig != null) {
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate 		AuthBlock.verifyAll(attrSig);
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate 	    }
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate 	    // Check whether the URL has a zero lifetime. If so, it
5350Sstevel@tonic-gate 	    // isn't cached.
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 	    if (surl.getLifetime() <= 0) {
5380Sstevel@tonic-gate 		throw
5390Sstevel@tonic-gate 		    new ServiceLocationException(errorCode,
5400Sstevel@tonic-gate 						 "st_zero",
5410Sstevel@tonic-gate 						 new Object[0]);
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate 	    }
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	    // Check if the service type is restricted. If so, nobody outside
5460Sstevel@tonic-gate 	    //  this process is allowed to register it.
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 	    checkForRestrictedType(surl.getServiceType());
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate 	    // Check that attribute signature bit on implies URL signature
5510Sstevel@tonic-gate 	    //  bit on.
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate 	    if (attrSig != null && urlSig == null) {
5540Sstevel@tonic-gate 		throw
5550Sstevel@tonic-gate 		    new ServiceLocationException(errorCode,
5560Sstevel@tonic-gate 						 "st_attr_sig",
5570Sstevel@tonic-gate 						 new Object[0]);
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 	    }
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 	    // If a signature and the fresh bit was not set, error since signed
5620Sstevel@tonic-gate 	    //  registrations don't allow updating.
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 	    if (urlSig != null && !fresh) {
5650Sstevel@tonic-gate 		throw
5660Sstevel@tonic-gate 		    new ServiceLocationException(
5670Sstevel@tonic-gate 				ServiceLocationException.INVALID_UPDATE,
5680Sstevel@tonic-gate 				"st_prot_update",
5690Sstevel@tonic-gate 				new Object[0]);
5700Sstevel@tonic-gate 	    }
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate 	    // Check if scopes are supported.
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	    if (!areSupportedScopes(scopes)) {
5750Sstevel@tonic-gate 		throw
5760Sstevel@tonic-gate 		    new ServiceLocationException(
5770Sstevel@tonic-gate 				ServiceLocationException.SCOPE_NOT_SUPPORTED,
5780Sstevel@tonic-gate 				"st_scope_unsup",
5790Sstevel@tonic-gate 				new Object[0]);
5800Sstevel@tonic-gate 	    }
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 	    // Check if the reg is signed and auth is off or vice versa.
5830Sstevel@tonic-gate 	    //  Check is really simple. If security is on, then all regs
5840Sstevel@tonic-gate 	    //  to this DA/SA server must be signed, so toss out any regs
5850Sstevel@tonic-gate 	    //  that aren't, and vice versa.
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 	    if (conf.getHasSecurity() && (urlSig == null || attrSig == null)) {
5880Sstevel@tonic-gate 		throw
5890Sstevel@tonic-gate 		    new ServiceLocationException(
5900Sstevel@tonic-gate 				ServiceLocationException.AUTHENTICATION_FAILED,
5910Sstevel@tonic-gate 				"st_unprot_non_reg",
5920Sstevel@tonic-gate 				new Object[0]);
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 	    } else if (!conf.getHasSecurity() &&
5950Sstevel@tonic-gate 		       (urlSig != null || attrSig != null)) {
5960Sstevel@tonic-gate 		throw
5970Sstevel@tonic-gate 		    new ServiceLocationException(
5980Sstevel@tonic-gate 				ServiceLocationException.INVALID_REGISTRATION,
5990Sstevel@tonic-gate 				"st_prot_non_reg",
6000Sstevel@tonic-gate 				new Object[0]);
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 	    }
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 	    // Merge any duplicates.
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate 	    Vector attrs = new Vector();
6070Sstevel@tonic-gate 	    Hashtable attrHash = new Hashtable();
6080Sstevel@tonic-gate 	    int i, n = attrList.size();
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 	    for (i = 0; i < n; i++) {
6110Sstevel@tonic-gate 		ServiceLocationAttribute attr =
6120Sstevel@tonic-gate 		    (ServiceLocationAttribute)attrList.elementAt(i);
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 		ServiceLocationAttribute.mergeDuplicateAttributes(
6150Sstevel@tonic-gate 								  attr,
6160Sstevel@tonic-gate 								  attrHash,
6170Sstevel@tonic-gate 								  attrs,
6180Sstevel@tonic-gate 								  false);
6190Sstevel@tonic-gate 	    }
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 	    // Store register or update.
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 	    boolean existing = false;
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	    if (fresh) {
6260Sstevel@tonic-gate 		existing = store.register(surl,
6270Sstevel@tonic-gate 					  attrs,
6280Sstevel@tonic-gate 					  scopes,
6290Sstevel@tonic-gate 					  locale,
6300Sstevel@tonic-gate 					  urlSig,
6310Sstevel@tonic-gate 					  attrSig);
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 		// Track registred service types in case we get a
6340Sstevel@tonic-gate 		// SAAdvert solicatation.
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate 		trackRegisteredServiceTypes();
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 	    } else {
6390Sstevel@tonic-gate 		store.updateRegistration(surl, attrs, scopes, locale);
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate 	    }
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 	    // Create the reply.
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 	    SrvLocMsg ack = req.makeReply(existing);
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 	    if (conf.regTest()) {
6480Sstevel@tonic-gate 		conf.writeLog((fresh ? "st_reg_add":"st_reg_update"),
6490Sstevel@tonic-gate 			      new Object[] {
6500Sstevel@tonic-gate 		    locationMsg,
6510Sstevel@tonic-gate 			locale,
6520Sstevel@tonic-gate 			serviceType,
6530Sstevel@tonic-gate 			surl,
6540Sstevel@tonic-gate 			attrs,
6550Sstevel@tonic-gate 			scopes});
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 	    }
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 	    if (conf.traceAll()) {
6600Sstevel@tonic-gate 		conf.writeLog("st_dump", new Object[] {locationMsg});
6610Sstevel@tonic-gate 		store.dumpServiceStore();
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 	    }
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate 	    // Calculate time increment until next update. This is used
6660Sstevel@tonic-gate 	    //  to adjust the sleep interval in the ager thread.
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate 	    long sTime = getSleepIncrement(surl);
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate 	    // We synchronize in case the ager thread is in the middle
6710Sstevel@tonic-gate 	    //  of trying to set the time.
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	    synchronized (store) {
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 		// If we need to wake up sooner, adjust the sleep time.
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate 		if (sTime < sleepyTime) {
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 		    sleepyTime = sTime;
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 		    // Interrupt the thread so we go back to
6820Sstevel@tonic-gate 		    //  sleep for the right amount of time.
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 		    thrAger.interrupt();
6850Sstevel@tonic-gate 		}
6860Sstevel@tonic-gate 	    }
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate 	    return ack;
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 	} catch (ServiceLocationException ex) {
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 	    if (conf.traceDrop()) {
6930Sstevel@tonic-gate 		conf.writeLog("st_reg_drop",
6940Sstevel@tonic-gate 			      new Object[] {
6950Sstevel@tonic-gate 		    locationMsg,
6960Sstevel@tonic-gate 			ex.getMessage()+"("+ex.getErrorCode()+")",
6970Sstevel@tonic-gate 			locale,
6980Sstevel@tonic-gate 			serviceType,
6990Sstevel@tonic-gate 			surl,
7000Sstevel@tonic-gate 			attrList,
7010Sstevel@tonic-gate 			scopes});
7020Sstevel@tonic-gate 	    }
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 	    return hdr.makeErrorReply(ex);
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 	} catch (RuntimeException ex) {
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	    // These exceptions are not declared in throws but can occur
7090Sstevel@tonic-gate 	    //  anywhere.
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 	    Vector args = new Vector();
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 	    args.addElement(req);
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 	    reportNonfatalException(ex, args, store);
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 	    return hdr.makeErrorReply(ex);
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate 	}
7200Sstevel@tonic-gate     }
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate     /**
7230Sstevel@tonic-gate      * Process the deregistration and return the result in a reply.
7240Sstevel@tonic-gate      *
7250Sstevel@tonic-gate      * @param req Service deregistration request message.
7260Sstevel@tonic-gate      * @return SrvLocMsg A service registration acknowledgement.
7270Sstevel@tonic-gate      */
7280Sstevel@tonic-gate 
deregister(SSrvDereg req)7290Sstevel@tonic-gate     SrvLocMsg deregister(SSrvDereg req) {
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 	// We need to determine whether this is an attribute deregistration
7320Sstevel@tonic-gate 	//  or a deregistration of the entire URL.
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 	SrvLocHeader hdr = req.getHeader();
7350Sstevel@tonic-gate 	Locale locale = hdr.locale;
7360Sstevel@tonic-gate 	Vector scopes = hdr.scopes;
7370Sstevel@tonic-gate 	ServiceURL surl = req.URL;
7380Sstevel@tonic-gate 	Hashtable urlSig = req.URLSignature;
7390Sstevel@tonic-gate 	Vector tags = req.tags;
7400Sstevel@tonic-gate 	short errorCode = ServiceLocationException.OK;
7410Sstevel@tonic-gate 
7420Sstevel@tonic-gate 	try {
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 	    // Verify if signature is nonnull.
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 	    if (urlSig != null) {
7470Sstevel@tonic-gate 		AuthBlock.verifyAll(urlSig);
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 	    }
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate 	    // Check if the service type is restricted. If so, nobody outside
7520Sstevel@tonic-gate 	    //  this process is allowed to register it.
7530Sstevel@tonic-gate 
7540Sstevel@tonic-gate 	    checkForRestrictedType(surl.getServiceType());
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 	    // Error if there's a signature and attempt at deleting attributes.
7570Sstevel@tonic-gate 
7580Sstevel@tonic-gate 	    if ((urlSig != null) && (tags != null)) {
7590Sstevel@tonic-gate 		throw
7600Sstevel@tonic-gate 		    new ServiceLocationException(
7610Sstevel@tonic-gate 				ServiceLocationException.AUTHENTICATION_FAILED,
7620Sstevel@tonic-gate 				"st_prot_attr_dereg",
7630Sstevel@tonic-gate 				new Object[0]);
7640Sstevel@tonic-gate 	    }
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 	    // Check if scope is protected and auth is off or vice versa.
7670Sstevel@tonic-gate 	    //  Check is really simple. If security is on, then all scopes
7680Sstevel@tonic-gate 	    //  in this DA/SA server are protected, so toss out any regs
7690Sstevel@tonic-gate 	    //  that aren't, and vice versa.
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate 	    if (conf.getHasSecurity() && urlSig == null) {
7720Sstevel@tonic-gate 		throw
7730Sstevel@tonic-gate 		    new ServiceLocationException(
7740Sstevel@tonic-gate 				ServiceLocationException.AUTHENTICATION_FAILED,
7750Sstevel@tonic-gate 				"st_unprot_non_dereg",
7760Sstevel@tonic-gate 				new Object[0]);
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 	    } else if (!conf.getHasSecurity() && urlSig != null) {
7790Sstevel@tonic-gate 		throw
7800Sstevel@tonic-gate 		    new ServiceLocationException(
7810Sstevel@tonic-gate 				ServiceLocationException.INVALID_REGISTRATION,
7820Sstevel@tonic-gate 				"st_prot_non_dereg",
7830Sstevel@tonic-gate 				new Object[0]);
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate 	    }
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 	    // If it's a service URL, then deregister the URL.
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 	    if (tags == null) {
7900Sstevel@tonic-gate 		store.deregister(surl, scopes, urlSig);
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 		// Track registred service types in case we get a
7930Sstevel@tonic-gate 		// SAAdvert solicatation.
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 		trackRegisteredServiceTypes();
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 	    } else {
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate 		// Just delete the attributes.
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 		store.deleteAttributes(surl, scopes, tags, locale);
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 	    }
8040Sstevel@tonic-gate 
8050Sstevel@tonic-gate 	    // Create the reply.
8060Sstevel@tonic-gate 
8070Sstevel@tonic-gate 	    SrvLocMsg ack = req.makeReply();
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 	    if (conf.regTest()) {
8100Sstevel@tonic-gate 		conf.writeLog((tags == null ? "st_dereg":"st_delattr"),
8110Sstevel@tonic-gate 			      new Object[] {
8120Sstevel@tonic-gate 		    locationMsg,
8130Sstevel@tonic-gate 	                locale,
8140Sstevel@tonic-gate 			surl.getServiceType(),
8150Sstevel@tonic-gate 			surl,
8160Sstevel@tonic-gate 			tags});
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 	    }
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 	    if (conf.traceAll()) {
8210Sstevel@tonic-gate 		conf.writeLog("st_dump",
8220Sstevel@tonic-gate 			      new Object[] {locationMsg});
8230Sstevel@tonic-gate 		store.dumpServiceStore();
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate 	    }
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate 	    return ack;
8280Sstevel@tonic-gate 
8290Sstevel@tonic-gate 	} catch (ServiceLocationException ex) {
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate 	    if (conf.traceDrop()) {
8320Sstevel@tonic-gate 		conf.writeLog((tags == null ?
8330Sstevel@tonic-gate 			       "st_dereg_drop" : "st_dereg_attr_drop"),
8340Sstevel@tonic-gate 			      new Object[] {
8350Sstevel@tonic-gate 		    locationMsg,
8360Sstevel@tonic-gate 			ex.getMessage()+"("+ex.getErrorCode()+")",
8370Sstevel@tonic-gate 			locale,
8380Sstevel@tonic-gate 			surl.getServiceType(),
8390Sstevel@tonic-gate 			surl,
8400Sstevel@tonic-gate 			tags});
8410Sstevel@tonic-gate 	    }
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 	    return hdr.makeErrorReply(ex);
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate 	} catch (RuntimeException ex) {
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate 	    // These exceptions are not declared in throws but can occur
8480Sstevel@tonic-gate 	    //  anywhere.
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 	    Vector args = new Vector();
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 	    args.addElement(req);
8530Sstevel@tonic-gate 
8540Sstevel@tonic-gate 	    reportNonfatalException(ex, args, store);
8550Sstevel@tonic-gate 
8560Sstevel@tonic-gate 	    return hdr.makeErrorReply(ex);
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate 	}
8590Sstevel@tonic-gate     }
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate     /**
8620Sstevel@tonic-gate      * Process the service type request and return the result in a reply.
8630Sstevel@tonic-gate      *
8640Sstevel@tonic-gate      * @param req Service type request message.
8650Sstevel@tonic-gate      * @return SrvTypeRply A service type reply.
8660Sstevel@tonic-gate      */
8670Sstevel@tonic-gate 
findServiceTypes(SSrvTypeMsg req)8680Sstevel@tonic-gate     SrvLocMsg findServiceTypes(SSrvTypeMsg req) {
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate 	SrvLocHeader hdr = req.getHeader();
8710Sstevel@tonic-gate 	Vector scopes = hdr.scopes;
8720Sstevel@tonic-gate 	String namingAuthority = req.namingAuthority;
8730Sstevel@tonic-gate 	short errorCode = ServiceLocationException.OK;
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 	try {
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate 	    // Check whether the scope is supported.
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate 	    if (!areSupportedScopes(scopes)) {
8800Sstevel@tonic-gate 		throw
8810Sstevel@tonic-gate 		    new ServiceLocationException(
8820Sstevel@tonic-gate 				ServiceLocationException.SCOPE_NOT_SUPPORTED,
8830Sstevel@tonic-gate 				"st_scope_unsup",
8840Sstevel@tonic-gate 				new Object[0]);
8850Sstevel@tonic-gate 
8860Sstevel@tonic-gate 	    }
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate 	    // Get the vector of service types in the store, independent
8890Sstevel@tonic-gate 	    //  of language.
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 	    Vector types = store.findServiceTypes(namingAuthority, scopes);
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate 	    // Create the reply.
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 	    SrvLocMsg ack = req.makeReply(types);
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate 	    if (conf.traceAll()) {
8980Sstevel@tonic-gate 		conf.writeLog("st_stypes",
8990Sstevel@tonic-gate 			      new Object[] {
9000Sstevel@tonic-gate 		    locationMsg,
9010Sstevel@tonic-gate 			namingAuthority,
9020Sstevel@tonic-gate 			scopes,
9030Sstevel@tonic-gate 			types});
9040Sstevel@tonic-gate 	    }
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 	    return ack;
9070Sstevel@tonic-gate 
9080Sstevel@tonic-gate 	} catch (ServiceLocationException ex) {
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate 	    if (conf.traceDrop()) {
9110Sstevel@tonic-gate 		conf.writeLog("st_stypes_drop",
9120Sstevel@tonic-gate 			      new Object[] {
9130Sstevel@tonic-gate 		    locationMsg,
9140Sstevel@tonic-gate 			ex.getMessage()+"("+ex.getErrorCode()+")",
9150Sstevel@tonic-gate 			namingAuthority,
9160Sstevel@tonic-gate 			scopes,
9170Sstevel@tonic-gate 			hdr.locale});
9180Sstevel@tonic-gate 	    }
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 	    return hdr.makeErrorReply(ex);
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate 	} catch (RuntimeException ex) {
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate 	    // These exceptions are not declared in throws but can occur
9250Sstevel@tonic-gate 	    //  anywhere.
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate 	    Vector args = new Vector();
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 	    args.addElement(req);
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate 	    reportNonfatalException(ex, args, store);
9320Sstevel@tonic-gate 
9330Sstevel@tonic-gate 	    return hdr.makeErrorReply(ex);
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 	}
9360Sstevel@tonic-gate     }
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate     /**
9390Sstevel@tonic-gate      * Process the service request and return the result in a reply.
9400Sstevel@tonic-gate      *
9410Sstevel@tonic-gate      * @param req Service request message.
9420Sstevel@tonic-gate      * @return SrvRply A service reply.
9430Sstevel@tonic-gate      */
9440Sstevel@tonic-gate 
findServices(SSrvMsg req)9450Sstevel@tonic-gate     SrvLocMsg findServices(SSrvMsg req) {
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate 	SrvLocHeader hdr = req.getHeader();
9480Sstevel@tonic-gate 	Locale locale = hdr.locale;
9490Sstevel@tonic-gate 	Vector scopes = hdr.scopes;
9500Sstevel@tonic-gate 	String serviceType = req.serviceType;
9510Sstevel@tonic-gate 	String query = req.query;
9520Sstevel@tonic-gate 	short errorCode = ServiceLocationException.OK;
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate 	try {
9550Sstevel@tonic-gate 
9560Sstevel@tonic-gate 	    // Check whether the scope is supported.
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate 	    if (!areSupportedScopes(scopes)) {
9590Sstevel@tonic-gate 		throw
9600Sstevel@tonic-gate 		    new ServiceLocationException(
9610Sstevel@tonic-gate 				ServiceLocationException.SCOPE_NOT_SUPPORTED,
9620Sstevel@tonic-gate 				"st_scope_unsup",
9630Sstevel@tonic-gate 				new Object[0]);
9640Sstevel@tonic-gate 	    }
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate 	    // Get the hashtable of returns.
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 	    Hashtable returns =
9690Sstevel@tonic-gate 		store.findServices(serviceType,
9700Sstevel@tonic-gate 				   scopes,
9710Sstevel@tonic-gate 				   query,
9720Sstevel@tonic-gate 				   locale);
9730Sstevel@tonic-gate 
9740Sstevel@tonic-gate 	    // Get the hashtable of services v.s. scopes, and signatures, if
9750Sstevel@tonic-gate 	    //  any.
9760Sstevel@tonic-gate 
9770Sstevel@tonic-gate 	    Hashtable services =
9780Sstevel@tonic-gate 		(Hashtable)returns.get(ServiceStore.FS_SERVICES);
9790Sstevel@tonic-gate 	    Hashtable signatures =
9800Sstevel@tonic-gate 		(Hashtable)returns.get(ServiceStore.FS_SIGTABLE);
9810Sstevel@tonic-gate 	    boolean hasSignatures = (signatures != null);
9820Sstevel@tonic-gate 
9830Sstevel@tonic-gate 	    // for each candidate URL, make sure it has the requested SPI
9840Sstevel@tonic-gate 	    // (if any)
9850Sstevel@tonic-gate 	    if (hasSignatures && !req.spi.equals("")) {
9860Sstevel@tonic-gate 		Enumeration allSurls = services.keys();
9870Sstevel@tonic-gate 		while (allSurls.hasMoreElements()) {
9880Sstevel@tonic-gate 		    Object aSurl = allSurls.nextElement();
9890Sstevel@tonic-gate 		    Hashtable auths = (Hashtable) signatures.get(aSurl);
9900Sstevel@tonic-gate 		    AuthBlock auth =
9910Sstevel@tonic-gate 			AuthBlock.getEquivalentAuth(req.spi, auths);
9920Sstevel@tonic-gate 		    if (auth == null) {
9930Sstevel@tonic-gate 			// doesn't have the requested SPI
9940Sstevel@tonic-gate 			services.remove(aSurl);
9950Sstevel@tonic-gate 		    }
9960Sstevel@tonic-gate 		}
9970Sstevel@tonic-gate 	    }
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate 	    // Create return message.
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate 	    SrvLocMsg ack = req.makeReply(services, signatures);
10020Sstevel@tonic-gate 
10030Sstevel@tonic-gate 	    if (conf.traceAll()) {
10040Sstevel@tonic-gate 		conf.writeLog("st_sreq",
10050Sstevel@tonic-gate 			      new Object[] {
10060Sstevel@tonic-gate 		    locationMsg,
10070Sstevel@tonic-gate 			serviceType,
10080Sstevel@tonic-gate 			scopes,
10090Sstevel@tonic-gate 			query,
10100Sstevel@tonic-gate 			locale,
10110Sstevel@tonic-gate 			services,
10120Sstevel@tonic-gate 			signatures});
10130Sstevel@tonic-gate 	    }
10140Sstevel@tonic-gate 
10150Sstevel@tonic-gate 	    return ack;
10160Sstevel@tonic-gate 
10170Sstevel@tonic-gate 	} catch (ServiceLocationException ex) {
10180Sstevel@tonic-gate 
10190Sstevel@tonic-gate 	    if (conf.traceDrop()) {
10200Sstevel@tonic-gate 		conf.writeLog("st_sreq_drop",
10210Sstevel@tonic-gate 			      new Object[] {
10220Sstevel@tonic-gate 		    locationMsg,
10230Sstevel@tonic-gate 			ex.getMessage()+"("+ex.getErrorCode()+")",
10240Sstevel@tonic-gate 			serviceType,
10250Sstevel@tonic-gate 			scopes,
10260Sstevel@tonic-gate 			query,
10270Sstevel@tonic-gate 			locale});
10280Sstevel@tonic-gate 	    }
10290Sstevel@tonic-gate 
10300Sstevel@tonic-gate 	    return hdr.makeErrorReply(ex);
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 	} catch (RuntimeException ex) {
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 	    // These exceptions are not declared in throws but can occur
10350Sstevel@tonic-gate 	    //  anywhere.
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 	    Vector args = new Vector();
10380Sstevel@tonic-gate 
10390Sstevel@tonic-gate 	    args.addElement(req);
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate 	    reportNonfatalException(ex, args, store);
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 	    return hdr.makeErrorReply(ex);
10440Sstevel@tonic-gate 
10450Sstevel@tonic-gate 	}
10460Sstevel@tonic-gate     }
10470Sstevel@tonic-gate 
10480Sstevel@tonic-gate     /**
10490Sstevel@tonic-gate      * Process the attribute request and return the result in a reply.
10500Sstevel@tonic-gate      *
10510Sstevel@tonic-gate      * @param req Attribute request message.
10520Sstevel@tonic-gate      * @return AttrRply An attribute reply.
10530Sstevel@tonic-gate      */
10540Sstevel@tonic-gate 
findAttributes(SAttrMsg req)10550Sstevel@tonic-gate     SrvLocMsg findAttributes(SAttrMsg req) {
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 	// We need to determine whether this is a request for attributes
10580Sstevel@tonic-gate 	//  on a specific URL or for an entire service type.
10590Sstevel@tonic-gate 
10600Sstevel@tonic-gate 	SrvLocHeader hdr = req.getHeader();
10610Sstevel@tonic-gate 	Vector scopes = hdr.scopes;
10620Sstevel@tonic-gate 	Locale locale = hdr.locale;
10630Sstevel@tonic-gate 	ServiceURL surl = req.URL;
10640Sstevel@tonic-gate 	String serviceType = req.serviceType;
10650Sstevel@tonic-gate 	Vector tags = req.tags;
10660Sstevel@tonic-gate 	short errorCode = ServiceLocationException.OK;
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate 	try {
10690Sstevel@tonic-gate 
10700Sstevel@tonic-gate 	    // Check whether the scope is supported.
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate 	    if (!areSupportedScopes(scopes)) {
10730Sstevel@tonic-gate 	throw
10740Sstevel@tonic-gate 	    new ServiceLocationException(
10750Sstevel@tonic-gate 				ServiceLocationException.SCOPE_NOT_SUPPORTED,
10760Sstevel@tonic-gate 				"st_scope_unsup",
10770Sstevel@tonic-gate 				new Object[0]);
10780Sstevel@tonic-gate 	    }
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate 	    Vector attributes = null;
10810Sstevel@tonic-gate 	    Hashtable sig = null;
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate 	    // If it's a service URL, then get the attributes just for
10840Sstevel@tonic-gate 	    // that URL.
10850Sstevel@tonic-gate 
10860Sstevel@tonic-gate 	    if (serviceType == null) {
10870Sstevel@tonic-gate 
10880Sstevel@tonic-gate 		// If the attrs are signed, then error if any tags, since
10890Sstevel@tonic-gate 		//  we must ask for *all* attributes in for a signed reg
10900Sstevel@tonic-gate 
10910Sstevel@tonic-gate 		if (!req.spi.equals("") && tags.size() > 0) {
10920Sstevel@tonic-gate 		    throw
10930Sstevel@tonic-gate 			new ServiceLocationException(
10940Sstevel@tonic-gate 				ServiceLocationException.AUTHENTICATION_FAILED,
10950Sstevel@tonic-gate 				"st_par_attr",
10960Sstevel@tonic-gate 				new Object[0]);
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 		}
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate 		Hashtable ht =
11010Sstevel@tonic-gate 		    store.findAttributes(surl, scopes, tags, locale);
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate 		// Get the attributes and signatures.
11040Sstevel@tonic-gate 
11050Sstevel@tonic-gate 		attributes = (Vector)ht.get(ServiceStore.FA_ATTRIBUTES);
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate 		sig = (Hashtable)ht.get(ServiceStore.FA_SIG);
11080Sstevel@tonic-gate 
11090Sstevel@tonic-gate 		// make sure the attr has the requested SPI (if any)
11100Sstevel@tonic-gate 		if (sig != null && !req.spi.equals("")) {
11110Sstevel@tonic-gate 		    AuthBlock auth = AuthBlock.getEquivalentAuth(req.spi, sig);
11120Sstevel@tonic-gate 		    if (auth == null) {
11130Sstevel@tonic-gate 			// return empty
11140Sstevel@tonic-gate 			attributes = new Vector();
11150Sstevel@tonic-gate 		    }
11160Sstevel@tonic-gate 		}
11170Sstevel@tonic-gate 
11180Sstevel@tonic-gate 	    } else {
11190Sstevel@tonic-gate 
11200Sstevel@tonic-gate 		if (!req.spi.equals("")) {
11210Sstevel@tonic-gate 		    throw
11220Sstevel@tonic-gate 			new ServiceLocationException(
11230Sstevel@tonic-gate 				ServiceLocationException.AUTHENTICATION_FAILED,
11240Sstevel@tonic-gate 				"st_par_attr",
11250Sstevel@tonic-gate 				new Object[0]);
11260Sstevel@tonic-gate 		}
11270Sstevel@tonic-gate 
11280Sstevel@tonic-gate 		// Otherwise find the attributes for all service types.
11290Sstevel@tonic-gate 
11300Sstevel@tonic-gate 		attributes =
11310Sstevel@tonic-gate 		    store.findAttributes(serviceType, scopes, tags, locale);
11320Sstevel@tonic-gate 
11330Sstevel@tonic-gate 	    }
11340Sstevel@tonic-gate 
11350Sstevel@tonic-gate 	    ServiceType type =
11360Sstevel@tonic-gate 		(serviceType == null ? surl.getServiceType():
11370Sstevel@tonic-gate 		 new ServiceType(serviceType));
11380Sstevel@tonic-gate 
11390Sstevel@tonic-gate 
11400Sstevel@tonic-gate 	    // Create the reply.
11410Sstevel@tonic-gate 
11420Sstevel@tonic-gate 	    SrvLocMsg ack = req.makeReply(attributes, sig);
11430Sstevel@tonic-gate 
11440Sstevel@tonic-gate 	    if (conf.traceAll()) {
11450Sstevel@tonic-gate 		conf.writeLog((serviceType != null ?
11460Sstevel@tonic-gate 			       "st_st_attr" : "st_url_attr"),
11470Sstevel@tonic-gate 			      new Object[] {
11480Sstevel@tonic-gate 		    locationMsg,
11490Sstevel@tonic-gate 			(serviceType != null ? serviceType.toString() :
11500Sstevel@tonic-gate 			 surl.toString()),
11510Sstevel@tonic-gate 		      	scopes,
11520Sstevel@tonic-gate 			tags,
11530Sstevel@tonic-gate 			locale,
11540Sstevel@tonic-gate 			attributes});
11550Sstevel@tonic-gate 	    }
11560Sstevel@tonic-gate 
11570Sstevel@tonic-gate 	    return ack;
11580Sstevel@tonic-gate 
11590Sstevel@tonic-gate 	} catch (ServiceLocationException ex) {
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate 	    if (conf.traceDrop()) {
11620Sstevel@tonic-gate 		conf.writeLog((serviceType != null ? "st_st_attr_drop":
11630Sstevel@tonic-gate 			       "st_url_attr_drop"),
11640Sstevel@tonic-gate 			      new Object[] {
11650Sstevel@tonic-gate 		    locationMsg,
11660Sstevel@tonic-gate 			ex.getMessage()+"("+ex.getErrorCode()+")",
11670Sstevel@tonic-gate 		        (serviceType != null ? serviceType.toString() :
11680Sstevel@tonic-gate 			 surl.toString()),
11690Sstevel@tonic-gate 		        scopes,
11700Sstevel@tonic-gate 			tags,
11710Sstevel@tonic-gate 			locale});
11720Sstevel@tonic-gate 	    }
11730Sstevel@tonic-gate 
11740Sstevel@tonic-gate 	    return hdr.makeErrorReply(ex);
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate 	} catch (RuntimeException ex) {
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate 	    // These exceptions are not declared in throws but can occur
11790Sstevel@tonic-gate 	    //  anywhere.
11800Sstevel@tonic-gate 
11810Sstevel@tonic-gate 	    Vector args = new Vector();
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate 	    args.addElement(req);
11840Sstevel@tonic-gate 
11850Sstevel@tonic-gate 	    reportNonfatalException(ex, args, store);
11860Sstevel@tonic-gate 
11870Sstevel@tonic-gate 	    return hdr.makeErrorReply(ex);
11880Sstevel@tonic-gate 
11890Sstevel@tonic-gate 	}
11900Sstevel@tonic-gate     }
11910Sstevel@tonic-gate 
11920Sstevel@tonic-gate     // Return the service record corresponding to the URL.
11930Sstevel@tonic-gate 
getServiceRecord(ServiceURL URL, Locale locale)11940Sstevel@tonic-gate     ServiceStore.ServiceRecord getServiceRecord(ServiceURL URL,
11950Sstevel@tonic-gate 						Locale locale) {
11960Sstevel@tonic-gate 	return store.getServiceRecord(URL, locale);
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate     }
11990Sstevel@tonic-gate 
12000Sstevel@tonic-gate     //
12010Sstevel@tonic-gate     // Utility methods.
12020Sstevel@tonic-gate     //
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate     //
12050Sstevel@tonic-gate     //  Protected/private methods.
12060Sstevel@tonic-gate     //
12070Sstevel@tonic-gate 
12080Sstevel@tonic-gate     // Check whether the type is restricted, through an exception if so.
12090Sstevel@tonic-gate 
checkForRestrictedType(ServiceType type)12100Sstevel@tonic-gate     private void checkForRestrictedType(ServiceType type)
12110Sstevel@tonic-gate 	throws ServiceLocationException {
12120Sstevel@tonic-gate 
12130Sstevel@tonic-gate 	if (Defaults.restrictedTypes.contains(type)) {
12140Sstevel@tonic-gate 	    throw
12150Sstevel@tonic-gate 		new ServiceLocationException(
12160Sstevel@tonic-gate 				ServiceLocationException.INVALID_REGISTRATION,
12170Sstevel@tonic-gate 				"st_restricted_type",
12180Sstevel@tonic-gate 				new Object[] {type});
12190Sstevel@tonic-gate 	}
12200Sstevel@tonic-gate     }
12210Sstevel@tonic-gate 
12220Sstevel@tonic-gate     // Insert a record for type "service-agent" with attributes having
12230Sstevel@tonic-gate     //  the types currently supported, if the new URL is not on the
12240Sstevel@tonic-gate     //  list of supported types. This allows us to perform queries
12250Sstevel@tonic-gate     //  for supported service types.
12260Sstevel@tonic-gate 
trackRegisteredServiceTypes()12270Sstevel@tonic-gate     private void trackRegisteredServiceTypes()
12280Sstevel@tonic-gate 	throws ServiceLocationException {
12290Sstevel@tonic-gate 
12300Sstevel@tonic-gate 	// First find the types.
12310Sstevel@tonic-gate 
12320Sstevel@tonic-gate 	Vector types = store.findServiceTypes(Defaults.ALL_AUTHORITIES,
12330Sstevel@tonic-gate 					      conf.getSAConfiguredScopes());
12340Sstevel@tonic-gate 
12350Sstevel@tonic-gate 	// Get preconfigured attributes.
12360Sstevel@tonic-gate 
12370Sstevel@tonic-gate 	Vector attrs = conf.getSAAttributes();
12380Sstevel@tonic-gate 
12390Sstevel@tonic-gate 	// Make an attribute with the service types.
12400Sstevel@tonic-gate 
12410Sstevel@tonic-gate 	ServiceLocationAttribute attr =
12420Sstevel@tonic-gate 	    new ServiceLocationAttribute(Defaults.SERVICE_TYPE_ATTR_ID,
12430Sstevel@tonic-gate 					 types);
12440Sstevel@tonic-gate 
12450Sstevel@tonic-gate 	attrs.addElement(attr);
12460Sstevel@tonic-gate 
12470Sstevel@tonic-gate 	// Construct URL to use on all interfaces.
12480Sstevel@tonic-gate 
12490Sstevel@tonic-gate 	Vector interfaces = conf.getInterfaces();
12500Sstevel@tonic-gate 	int i, n = interfaces.size();
12510Sstevel@tonic-gate 
12520Sstevel@tonic-gate 	for (i = 0; i < n; i++) {
12530Sstevel@tonic-gate 	    InetAddress addr = (InetAddress)interfaces.elementAt(i);
12540Sstevel@tonic-gate 	    ServiceURL url =
12550Sstevel@tonic-gate 		new ServiceURL(Defaults.SUN_SA_SERVICE_TYPE + "://" +
12560Sstevel@tonic-gate 			       addr.getHostAddress(),
12570Sstevel@tonic-gate 			       ServiceURL.LIFETIME_MAXIMUM);
12580Sstevel@tonic-gate 
12590Sstevel@tonic-gate 	    Vector scopes = conf.getSAOnlyScopes();
12600Sstevel@tonic-gate 
12610Sstevel@tonic-gate 	    Locale locale = Defaults.locale;
12620Sstevel@tonic-gate 
12630Sstevel@tonic-gate 	    // Make a new registration for this SA.
12640Sstevel@tonic-gate 
12650Sstevel@tonic-gate 	    store.register(url,
12660Sstevel@tonic-gate 			   attrs,
12670Sstevel@tonic-gate 			   scopes,
12680Sstevel@tonic-gate 			   locale,
12690Sstevel@tonic-gate 			   null,
12700Sstevel@tonic-gate 			   null);  // we could sign, but we do that later...
12710Sstevel@tonic-gate 	}
12720Sstevel@tonic-gate 
12730Sstevel@tonic-gate 	// Note that we don't need a refresh on the URLs because they
12740Sstevel@tonic-gate 	//  will get refreshed when the service URLs that they track
12750Sstevel@tonic-gate 	//  are refreshed. If the tracked URLs aren't refreshed, then
12760Sstevel@tonic-gate 	//  these will get updated when the tracked URLs age out.
12770Sstevel@tonic-gate     }
12780Sstevel@tonic-gate 
12790Sstevel@tonic-gate     // Return true if the scopes in the vector are supported by the DA
12800Sstevel@tonic-gate     //  or SA server.
12810Sstevel@tonic-gate 
areSupportedScopes(Vector scopes)12820Sstevel@tonic-gate     final private boolean areSupportedScopes(Vector scopes) {
12830Sstevel@tonic-gate 
12840Sstevel@tonic-gate 	Vector configuredScopes = conf.getSAConfiguredScopes();
12850Sstevel@tonic-gate 	Vector saOnlyScopes = conf.getSAOnlyScopes();
12860Sstevel@tonic-gate 	int i = 0;
12870Sstevel@tonic-gate 
12880Sstevel@tonic-gate 	while (i < scopes.size()) {
12890Sstevel@tonic-gate 	    Object o = scopes.elementAt(i);
12900Sstevel@tonic-gate 
12910Sstevel@tonic-gate 	    // Remove it if we don't support it.
12920Sstevel@tonic-gate 
12930Sstevel@tonic-gate 	    if (!configuredScopes.contains(o) && !saOnlyScopes.contains(o)) {
12940Sstevel@tonic-gate 		// This will shift the Vector's elements down one, so
12950Sstevel@tonic-gate 		// don't increment i
12960Sstevel@tonic-gate 		scopes.removeElementAt(i);
12970Sstevel@tonic-gate 	    } else {
12980Sstevel@tonic-gate 		i++;
12990Sstevel@tonic-gate 	    }
13000Sstevel@tonic-gate 	}
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate 	if (scopes.size() <= 0) {
13030Sstevel@tonic-gate 	    return false;
13040Sstevel@tonic-gate 
13050Sstevel@tonic-gate 	}
13060Sstevel@tonic-gate 
13070Sstevel@tonic-gate 	return true;
13080Sstevel@tonic-gate     }
13090Sstevel@tonic-gate 
13100Sstevel@tonic-gate     /**
13110Sstevel@tonic-gate      * Return the sleep increment from the URL lifetime. Used by the
13120Sstevel@tonic-gate      * ServiceStore to calculate the new sleep interval in addition
13130Sstevel@tonic-gate      * to this class, when a new URL comes in. The algorithm
13140Sstevel@tonic-gate      * subtracts x% of the lifetime from the lifetime and schedules the
13150Sstevel@tonic-gate      * timeout at that time.
13160Sstevel@tonic-gate      *
13170Sstevel@tonic-gate      * @param url The URL to use for calculation.
13180Sstevel@tonic-gate      * @return The sleep interval.
13190Sstevel@tonic-gate      */
13200Sstevel@tonic-gate 
getSleepIncrement(ServiceURL url)13210Sstevel@tonic-gate     private long getSleepIncrement(ServiceURL url) {
13220Sstevel@tonic-gate 	long urlLifetime = (long)(url.getLifetime() * 1000);
13230Sstevel@tonic-gate 	long increment =
13240Sstevel@tonic-gate 	    (long)((float)urlLifetime * Defaults.fRefreshGranularity);
13250Sstevel@tonic-gate 	long sTime = urlLifetime - increment;
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate 	// If URL lives only one second, update every half second.
13280Sstevel@tonic-gate 
13290Sstevel@tonic-gate 	if (sTime <= 0) {
13300Sstevel@tonic-gate 	    sTime = 500;
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate 	}
13330Sstevel@tonic-gate 
13340Sstevel@tonic-gate 	return sTime;
13350Sstevel@tonic-gate     }
13360Sstevel@tonic-gate 
13370Sstevel@tonic-gate     // Make a DAADvert for the DA service request. This only applies
13380Sstevel@tonic-gate     //  to DAs, not to SA servers.
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate     SrvLocMsg
makeDAAdvert(SSrvMsg rqst, InetAddress daAddr, SLPConfig conf)13410Sstevel@tonic-gate 	makeDAAdvert(SSrvMsg rqst,
13420Sstevel@tonic-gate 		     InetAddress daAddr,
13430Sstevel@tonic-gate 		     SLPConfig conf) {
13440Sstevel@tonic-gate 
13450Sstevel@tonic-gate 	SrvLocHeader hdr = rqst.getHeader();
13460Sstevel@tonic-gate 	Vector scopes = hdr.scopes;
13470Sstevel@tonic-gate 	short xid = hdr.xid;
13480Sstevel@tonic-gate 	String query = rqst.query;
13490Sstevel@tonic-gate 
13500Sstevel@tonic-gate 	try {
13510Sstevel@tonic-gate 
13520Sstevel@tonic-gate 	    // If security is on, proceed only if we can sign as rqst.spi
13530Sstevel@tonic-gate 	    if (conf.getHasSecurity() && !AuthBlock.canSignAs(rqst.spi)) {
13540Sstevel@tonic-gate 		throw new ServiceLocationException(
13550Sstevel@tonic-gate 			ServiceLocationException.AUTHENTICATION_UNKNOWN,
13560Sstevel@tonic-gate 			"st_cant_sign_as",
13570Sstevel@tonic-gate 			new Object[] {rqst.spi});
13580Sstevel@tonic-gate 	    }
13590Sstevel@tonic-gate 
13600Sstevel@tonic-gate 	    // Get the hashtable of service URLs v.s. scopes.
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate 	    Hashtable services =
13630Sstevel@tonic-gate 		ServerDATable.getServerDATable().returnMatchingDAs(query);
13640Sstevel@tonic-gate 
13650Sstevel@tonic-gate 	    // Go through the table checking whether the IP address came back.
13660Sstevel@tonic-gate 
13670Sstevel@tonic-gate 	    Enumeration urls = services.keys();
13680Sstevel@tonic-gate 	    boolean foundIt = false;
13690Sstevel@tonic-gate 	    String strDAAddr = daAddr.getHostAddress();
13700Sstevel@tonic-gate 
13710Sstevel@tonic-gate 	    while (urls.hasMoreElements()) {
13720Sstevel@tonic-gate 		ServiceURL url = (ServiceURL)urls.nextElement();
13730Sstevel@tonic-gate 
13740Sstevel@tonic-gate 		if (url.getHost().equals(strDAAddr)) {
13750Sstevel@tonic-gate 		    foundIt = true;
13760Sstevel@tonic-gate 		    break;
13770Sstevel@tonic-gate 
13780Sstevel@tonic-gate 		}
13790Sstevel@tonic-gate 	    }
13800Sstevel@tonic-gate 
13810Sstevel@tonic-gate 	    // If we didn't find anything, make a null service reply.
13820Sstevel@tonic-gate 
13830Sstevel@tonic-gate 	    if (!foundIt) {
13840Sstevel@tonic-gate 		return rqst.makeReply(new Hashtable(), new Hashtable());
13850Sstevel@tonic-gate 
13860Sstevel@tonic-gate 	    }
13870Sstevel@tonic-gate 
13880Sstevel@tonic-gate 	    return makeDAAdvert(hdr, daAddr, xid, scopes, conf);
13890Sstevel@tonic-gate 
13900Sstevel@tonic-gate 
13910Sstevel@tonic-gate 	} catch (ServiceLocationException ex) {
13920Sstevel@tonic-gate 
13930Sstevel@tonic-gate 	    return hdr.makeErrorReply(ex);
13940Sstevel@tonic-gate 
13950Sstevel@tonic-gate 	}
13960Sstevel@tonic-gate 
13970Sstevel@tonic-gate     }
13980Sstevel@tonic-gate 
13990Sstevel@tonic-gate     // Make a DAAdvert from the input arguments.
14000Sstevel@tonic-gate     SrvLocMsg
makeDAAdvert(SrvLocHeader hdr, InetAddress daAddr, short xid, Vector scopes, SLPConfig config)14010Sstevel@tonic-gate 	makeDAAdvert(SrvLocHeader hdr,
14020Sstevel@tonic-gate 		     InetAddress daAddr,
14030Sstevel@tonic-gate 		     short xid,
14040Sstevel@tonic-gate 		     Vector scopes,
14050Sstevel@tonic-gate 		     SLPConfig config)
14060Sstevel@tonic-gate 	throws ServiceLocationException {
14070Sstevel@tonic-gate 
14080Sstevel@tonic-gate 	// If this is a request for a V1 Advert, truncate the scopes vector
14090Sstevel@tonic-gate 	//  since DA solicitations in V1 are always unscoped
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate 	if (hdr.version == 1) {
14120Sstevel@tonic-gate 	    scopes = new Vector();
14130Sstevel@tonic-gate 
14140Sstevel@tonic-gate 	}
14150Sstevel@tonic-gate 
14160Sstevel@tonic-gate 	// Check if we support scopes first. If not, return an
14170Sstevel@tonic-gate 	//  error reply unless the scope vector is zero. Upper layers
14180Sstevel@tonic-gate 	//  must sort out whether this is a unicast or multicast.
14190Sstevel@tonic-gate 
14200Sstevel@tonic-gate 	if (scopes.size() > 0 && !areSupportedScopes(scopes)) {
14210Sstevel@tonic-gate 	    throw
14220Sstevel@tonic-gate 		new ServiceLocationException(
14230Sstevel@tonic-gate 				ServiceLocationException.SCOPE_NOT_SUPPORTED,
14240Sstevel@tonic-gate 				"st_scope_unsup",
14250Sstevel@tonic-gate 				new Object[0]);
14260Sstevel@tonic-gate 
14270Sstevel@tonic-gate 	}
14280Sstevel@tonic-gate 
14290Sstevel@tonic-gate 	// Get the service store's timestamp. This must be the
14300Sstevel@tonic-gate 	//  time since last stateless reboot for a stateful store,
14310Sstevel@tonic-gate 	//  or the current time.
14320Sstevel@tonic-gate 
14330Sstevel@tonic-gate 	long timestamp = store.getStateTimestamp();
14340Sstevel@tonic-gate 
14350Sstevel@tonic-gate 	ServiceURL url =
14360Sstevel@tonic-gate 	    new ServiceURL(Defaults.DA_SERVICE_TYPE + "://" +
14370Sstevel@tonic-gate 			   daAddr.getHostAddress(),
14380Sstevel@tonic-gate 			   ServiceURL.LIFETIME_DEFAULT);
14390Sstevel@tonic-gate 
14400Sstevel@tonic-gate 	SDAAdvert advert =
14410Sstevel@tonic-gate 	    hdr.getDAAdvert(xid,
14420Sstevel@tonic-gate 			    timestamp,
14430Sstevel@tonic-gate 			    url,
14440Sstevel@tonic-gate 			    scopes,
14450Sstevel@tonic-gate 			    conf.getDAAttributes());
14460Sstevel@tonic-gate 
14470Sstevel@tonic-gate 	return advert;
14480Sstevel@tonic-gate     }
14490Sstevel@tonic-gate 
14500Sstevel@tonic-gate     // Make a SAADvert for the SA service request. This only applies
14510Sstevel@tonic-gate     //  to SA servers, not DA's. Note that we only advertise the "public"
14520Sstevel@tonic-gate     //  scopes, not the private ones.
14530Sstevel@tonic-gate 
14540Sstevel@tonic-gate     SSAAdvert
makeSAAdvert(SSrvMsg rqst, InetAddress interfac, SLPConfig conf)14550Sstevel@tonic-gate 	makeSAAdvert(SSrvMsg rqst,
14560Sstevel@tonic-gate 		     InetAddress interfac,
14570Sstevel@tonic-gate 		     SLPConfig conf)
14580Sstevel@tonic-gate 	throws ServiceLocationException {
14590Sstevel@tonic-gate 	SrvLocHeader hdr = rqst.getHeader();
14600Sstevel@tonic-gate 	int version = hdr.version;
14610Sstevel@tonic-gate 	short xid = hdr.xid;
14620Sstevel@tonic-gate 	Locale locale = hdr.locale;
14630Sstevel@tonic-gate 	Vector scopes = hdr.scopes;
14640Sstevel@tonic-gate 	String query = rqst.query;
14650Sstevel@tonic-gate 	String serviceType = rqst.serviceType;
14660Sstevel@tonic-gate 	Vector saOnlyScopes = conf.getSAOnlyScopes();
14670Sstevel@tonic-gate 
14680Sstevel@tonic-gate 	// If security is on, proceed only if we can sign as rqst.spi
14690Sstevel@tonic-gate 	if (conf.getHasSecurity() && !AuthBlock.canSignAs(rqst.spi)) {
14700Sstevel@tonic-gate 	    throw new ServiceLocationException(
14710Sstevel@tonic-gate 			ServiceLocationException.AUTHENTICATION_UNKNOWN,
14720Sstevel@tonic-gate 			"st_cant_sign_as",
14730Sstevel@tonic-gate 			new Object[] {rqst.spi});
14740Sstevel@tonic-gate 	}
14750Sstevel@tonic-gate 
14760Sstevel@tonic-gate 
14770Sstevel@tonic-gate 	// Check if we support scopes first. Note that this may allow
14780Sstevel@tonic-gate 	//  someone to get at the SA only scopes off machine, but that's
14790Sstevel@tonic-gate 	//  OK. Since the SAAdvert is only ever multicast, this is OK.
14800Sstevel@tonic-gate 
14810Sstevel@tonic-gate 	if (!areSupportedScopes(scopes) && !(scopes.size() <= 0)) {
14820Sstevel@tonic-gate 	    return null;
14830Sstevel@tonic-gate 
14840Sstevel@tonic-gate 	}
14850Sstevel@tonic-gate 
14860Sstevel@tonic-gate 	// If the scopes vector is null, then use all configured scopes.
14870Sstevel@tonic-gate 
14880Sstevel@tonic-gate 	if (scopes.size() <= 0) {
14890Sstevel@tonic-gate 	    scopes = (Vector)conf.getSAConfiguredScopes().clone();
14900Sstevel@tonic-gate 
14910Sstevel@tonic-gate 	}
14920Sstevel@tonic-gate 
14930Sstevel@tonic-gate 	// Check to be sure the query matches.
14940Sstevel@tonic-gate 	//  If it doesn't, we don't need to return anything.
14950Sstevel@tonic-gate 
14960Sstevel@tonic-gate 	Hashtable returns =
14970Sstevel@tonic-gate 	    store.findServices(Defaults.SUN_SA_SERVICE_TYPE.toString(),
14980Sstevel@tonic-gate 			       saOnlyScopes,
14990Sstevel@tonic-gate 			       query,
15000Sstevel@tonic-gate 			       Defaults.locale);
15010Sstevel@tonic-gate 	Hashtable services =
15020Sstevel@tonic-gate 	    (Hashtable)returns.get(ServiceStore.FS_SERVICES);
15030Sstevel@tonic-gate 	Enumeration en = services.keys();
15040Sstevel@tonic-gate 
15050Sstevel@tonic-gate 	// Indicates we don't support the service type.
15060Sstevel@tonic-gate 
15070Sstevel@tonic-gate 	if (!en.hasMoreElements()) {
15080Sstevel@tonic-gate 	    return null;
15090Sstevel@tonic-gate 
15100Sstevel@tonic-gate 	}
15110Sstevel@tonic-gate 
15120Sstevel@tonic-gate 	// Find the URL to use. The interface on which the message came in
15130Sstevel@tonic-gate 	//  needs to match one of the registered URLs.
15140Sstevel@tonic-gate 
15150Sstevel@tonic-gate 	ServiceURL url = null;
15160Sstevel@tonic-gate 	ServiceURL surl = null;
15170Sstevel@tonic-gate 	String addr = interfac.getHostAddress();
15180Sstevel@tonic-gate 
15190Sstevel@tonic-gate 	while (en.hasMoreElements()) {
15200Sstevel@tonic-gate 	    surl = (ServiceURL)en.nextElement();
15210Sstevel@tonic-gate 
15220Sstevel@tonic-gate 	    if (addr.equals(surl.getHost())) {
15230Sstevel@tonic-gate 		url = new ServiceURL(Defaults.SA_SERVICE_TYPE + "://" +
15240Sstevel@tonic-gate 				     addr,
15250Sstevel@tonic-gate 				     ServiceURL.LIFETIME_DEFAULT);
15260Sstevel@tonic-gate 		break;
15270Sstevel@tonic-gate 	    }
15280Sstevel@tonic-gate 	}
15290Sstevel@tonic-gate 
15300Sstevel@tonic-gate 	// If none of the URLs matched this interface, then return null.
15310Sstevel@tonic-gate 
15320Sstevel@tonic-gate 	if (url == null) {
15330Sstevel@tonic-gate 	    return null;
15340Sstevel@tonic-gate 
15350Sstevel@tonic-gate 	}
15360Sstevel@tonic-gate 
15370Sstevel@tonic-gate 	// Find the SA's attributes.
15380Sstevel@tonic-gate 
15390Sstevel@tonic-gate 	Hashtable ht =
15400Sstevel@tonic-gate 	    store.findAttributes(surl,
15410Sstevel@tonic-gate 				 saOnlyScopes,
15420Sstevel@tonic-gate 				 new Vector(),
15430Sstevel@tonic-gate 				 Defaults.locale);
15440Sstevel@tonic-gate 
15450Sstevel@tonic-gate 	Vector attrs = (Vector)ht.get(ServiceStore.FA_ATTRIBUTES);
15460Sstevel@tonic-gate 
15470Sstevel@tonic-gate 	// Construct return.
15480Sstevel@tonic-gate 
15490Sstevel@tonic-gate 	return
15500Sstevel@tonic-gate 	    new SSAAdvert(version,
15510Sstevel@tonic-gate 			  xid,
15520Sstevel@tonic-gate 			  locale,
15530Sstevel@tonic-gate 			  url,
15540Sstevel@tonic-gate 			  conf.getSAConfiguredScopes(), // report all scopes...
15550Sstevel@tonic-gate 			  attrs);
15560Sstevel@tonic-gate     }
15570Sstevel@tonic-gate 
15580Sstevel@tonic-gate     /**
15590Sstevel@tonic-gate      * Report a fatal exception to the log.
15600Sstevel@tonic-gate      *
15610Sstevel@tonic-gate      * @param ex The exception to report.
15620Sstevel@tonic-gate      */
15630Sstevel@tonic-gate 
reportFatalException(Exception ex)15640Sstevel@tonic-gate     protected static void reportFatalException(Exception ex) {
15650Sstevel@tonic-gate 
15660Sstevel@tonic-gate 	reportException(true, ex, new Vector());
15670Sstevel@tonic-gate 
15680Sstevel@tonic-gate 	if (table != null) {
15690Sstevel@tonic-gate 	    table.store.dumpServiceStore();
15700Sstevel@tonic-gate 	}
15710Sstevel@tonic-gate 
15720Sstevel@tonic-gate 	conf.writeLog("exiting_msg", new Object[0]);
15730Sstevel@tonic-gate 
15740Sstevel@tonic-gate 	System.exit(1);
15750Sstevel@tonic-gate 
15760Sstevel@tonic-gate     }
15770Sstevel@tonic-gate 
15780Sstevel@tonic-gate     /**
15790Sstevel@tonic-gate      * Report a nonfatal exception to the log.
15800Sstevel@tonic-gate      *
15810Sstevel@tonic-gate      * @param ex The exception to report.
15820Sstevel@tonic-gate      * @param args The method arguments.
15830Sstevel@tonic-gate      * @param store The service store being processed.
15840Sstevel@tonic-gate      */
15850Sstevel@tonic-gate 
reportNonfatalException(Exception ex, Vector args, ServiceStore store)15860Sstevel@tonic-gate     protected static void reportNonfatalException(Exception ex,
15870Sstevel@tonic-gate 						  Vector args,
15880Sstevel@tonic-gate 						  ServiceStore store) {
15890Sstevel@tonic-gate 
15900Sstevel@tonic-gate 	reportException(false, ex, args);
15910Sstevel@tonic-gate 
15920Sstevel@tonic-gate 	if (conf.traceAll()) {
15930Sstevel@tonic-gate 	    store.dumpServiceStore();
15940Sstevel@tonic-gate 	}
15950Sstevel@tonic-gate 
15960Sstevel@tonic-gate     }
15970Sstevel@tonic-gate 
15980Sstevel@tonic-gate     /**
15990Sstevel@tonic-gate      * Report an exception to the log.
16000Sstevel@tonic-gate      *
16010Sstevel@tonic-gate      * @param isFatal Indicates whether the exception is fatal or not.
16020Sstevel@tonic-gate      * @param ex The exception to report.
16030Sstevel@tonic-gate      * @param args A potentially null vector of arguments to the
16040Sstevel@tonic-gate      * 			method where the exception was caught.
16050Sstevel@tonic-gate      */
16060Sstevel@tonic-gate 
16070Sstevel@tonic-gate     private static void
reportException(boolean isFatal, Exception ex, Vector args)16080Sstevel@tonic-gate 	reportException(boolean isFatal, Exception ex, Vector args) {
16090Sstevel@tonic-gate 
16100Sstevel@tonic-gate 	StringWriter sw = new StringWriter();
16110Sstevel@tonic-gate 	PrintWriter writer = new PrintWriter(sw);
16120Sstevel@tonic-gate 
16130Sstevel@tonic-gate 	// Get the backtrace.
16140Sstevel@tonic-gate 
16150Sstevel@tonic-gate 	ex.printStackTrace(writer);
16160Sstevel@tonic-gate 
16170Sstevel@tonic-gate 	String severity = (isFatal ? "fatal_error":"nonfatal_error");
16180Sstevel@tonic-gate 	String msg = ex.getMessage();
16190Sstevel@tonic-gate 
16200Sstevel@tonic-gate 	if (msg == null) {
16210Sstevel@tonic-gate 	    msg = conf.formatMessage("no_message", new Object[0]);
16220Sstevel@tonic-gate 
16230Sstevel@tonic-gate 	} else if (ex instanceof ServiceLocationException) {
16240Sstevel@tonic-gate 	    msg = msg +
16250Sstevel@tonic-gate 		"(" + ((ServiceLocationException)ex).getErrorCode() + ")";
16260Sstevel@tonic-gate 
16270Sstevel@tonic-gate 	}
16280Sstevel@tonic-gate 
16290Sstevel@tonic-gate 	StringBuffer argMsg = new StringBuffer();
16300Sstevel@tonic-gate 
16310Sstevel@tonic-gate 	int i, n = args.size();
16320Sstevel@tonic-gate 
16330Sstevel@tonic-gate 	for (i = 0; i < n; i++) {
16340Sstevel@tonic-gate 	    argMsg.append("\n        (" + Integer.toString(i) + "):" +
16350Sstevel@tonic-gate 			  args.elementAt(i).toString());
16360Sstevel@tonic-gate 	}
16370Sstevel@tonic-gate 
16380Sstevel@tonic-gate 	conf.writeLog(severity,
16390Sstevel@tonic-gate 		      new Object[] {
16400Sstevel@tonic-gate 	    ex.getClass().getName(),
16410Sstevel@tonic-gate 		msg,
16420Sstevel@tonic-gate 		argMsg,
16430Sstevel@tonic-gate 		sw.toString()});
16440Sstevel@tonic-gate 
16450Sstevel@tonic-gate     }
16460Sstevel@tonic-gate }
1647