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 //  SLPTemplateRegistry.java: Service object for registering a new service
280Sstevel@tonic-gate //			  template.
290Sstevel@tonic-gate //  Author:           James Kempf
300Sstevel@tonic-gate //  Created On:       Tue May 27 15:04:35 1997
310Sstevel@tonic-gate //  Last Modified By: James Kempf
320Sstevel@tonic-gate //  Last Modified On: Thu Jan  7 14:25:20 1999
330Sstevel@tonic-gate //  Update Count:     134
340Sstevel@tonic-gate //
350Sstevel@tonic-gate 
360Sstevel@tonic-gate package com.sun.slp;
370Sstevel@tonic-gate 
380Sstevel@tonic-gate import java.util.*;
390Sstevel@tonic-gate 
400Sstevel@tonic-gate /**
410Sstevel@tonic-gate  * The SLPTemplateRegistry class registers and unregisters service templates,
420Sstevel@tonic-gate  * looks up the template based on the service type name, and returns an
430Sstevel@tonic-gate  * attribute verifier for the service.It subclasses the TemplateRegistry
440Sstevel@tonic-gate  * abstract class.
450Sstevel@tonic-gate  *
460Sstevel@tonic-gate  * An slp-template URL has the following format:
470Sstevel@tonic-gate  *
480Sstevel@tonic-gate  *   service:slp-template:<document URL>;type=<service type>;
490Sstevel@tonic-gate  *				          version=<version no.>;
500Sstevel@tonic-gate  *					  language=<language locale>
510Sstevel@tonic-gate  *
520Sstevel@tonic-gate  * @author James Kempf
530Sstevel@tonic-gate  *
540Sstevel@tonic-gate  */
550Sstevel@tonic-gate 
560Sstevel@tonic-gate class SLPTemplateRegistry extends TemplateRegistry {
570Sstevel@tonic-gate 
580Sstevel@tonic-gate     /**
590Sstevel@tonic-gate      * Attribute id for attribute describing service type name.
600Sstevel@tonic-gate      * String, single valued attribute.
610Sstevel@tonic-gate      */
620Sstevel@tonic-gate 
630Sstevel@tonic-gate     static final String SERVICE_ATTR_ID = "template-type";
640Sstevel@tonic-gate 
650Sstevel@tonic-gate     /**
660Sstevel@tonic-gate      * Attribute id for attribute describing help text.
670Sstevel@tonic-gate      * String, single valued, required attribute, .
680Sstevel@tonic-gate      */
690Sstevel@tonic-gate 
700Sstevel@tonic-gate     static final String DESCRIPTION_ATTR_ID = "template-description";
710Sstevel@tonic-gate 
720Sstevel@tonic-gate     /**
730Sstevel@tonic-gate      * Attribute id for attribute describing service version. The
740Sstevel@tonic-gate      * version number is of the form ``n.m'', where n and m are integers.
750Sstevel@tonic-gate      * String, single valued, required attribute.
760Sstevel@tonic-gate      */
770Sstevel@tonic-gate 
780Sstevel@tonic-gate     static final String VERSION_ATTR_ID = "template-version";
790Sstevel@tonic-gate 
800Sstevel@tonic-gate     /**
810Sstevel@tonic-gate      * Attribute id for attribute describing service URL url part grammer.
820Sstevel@tonic-gate      * String, single valued, required attribute.
830Sstevel@tonic-gate      */
840Sstevel@tonic-gate 
850Sstevel@tonic-gate     static final String SERVICE_URL_ATTR_ID = "template-url-syntax";
860Sstevel@tonic-gate 
870Sstevel@tonic-gate     /**
880Sstevel@tonic-gate      * The service type name for the template type.
890Sstevel@tonic-gate      */
900Sstevel@tonic-gate 
910Sstevel@tonic-gate     static final String TEMPLATE_SERVICE_TYPE = "service:slp-template";
920Sstevel@tonic-gate 
930Sstevel@tonic-gate     // The distinguished template registry object.
940Sstevel@tonic-gate 
950Sstevel@tonic-gate     private static TemplateRegistry registry = null;
960Sstevel@tonic-gate 
970Sstevel@tonic-gate     // Package private constructor for singleton pattern maintained
980Sstevel@tonic-gate     // by the ServiceLocationManager.
990Sstevel@tonic-gate 
SLPTemplateRegistry()1000Sstevel@tonic-gate     SLPTemplateRegistry() throws ServiceLocationException {
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate     }
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate     //
1050Sstevel@tonic-gate     // Public implementation.
1060Sstevel@tonic-gate     //
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate     /**
1090Sstevel@tonic-gate      * Register the new service.
1100Sstevel@tonic-gate      *
1110Sstevel@tonic-gate      * @param serviceType	Name of the service.
1120Sstevel@tonic-gate      * @param documentURL	URL of the template document.
1130Sstevel@tonic-gate      * @param languageLocale	Locale of the template langugae.
1140Sstevel@tonic-gate      * @param version		Version number of template document.
1150Sstevel@tonic-gate      * @exception ServiceLocationException Error code is
1160Sstevel@tonic-gate      *				    INVALID_REGISTRATION
1170Sstevel@tonic-gate      *					   if the service already exists or
1180Sstevel@tonic-gate      *					   the registration fails.
1190Sstevel@tonic-gate      *					   Throws
1200Sstevel@tonic-gate      *				    SYSTEM_ERROR
1210Sstevel@tonic-gate      *					   if the scope vector is null or
1220Sstevel@tonic-gate      *					   empty.
1230Sstevel@tonic-gate      *					   Throws
1240Sstevel@tonic-gate      *				    PARSE_ERROR
1250Sstevel@tonic-gate      *					   if an attribute is bad.
1260Sstevel@tonic-gate      * @exception IllegalArgumentException Thrown if any parameters are null.
1270Sstevel@tonic-gate      *
1280Sstevel@tonic-gate      */
1290Sstevel@tonic-gate 
registerServiceTemplate(ServiceType serviceType, String documentURL, Locale languageLocale, String version)1300Sstevel@tonic-gate     public void registerServiceTemplate(ServiceType serviceType,
1310Sstevel@tonic-gate 					String documentURL,
1320Sstevel@tonic-gate 					Locale languageLocale,
1330Sstevel@tonic-gate 					String version)
1340Sstevel@tonic-gate 	throws ServiceLocationException {
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 	// Check for illegal parameters.
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 	Assert.nonNullParameter(serviceType, "serviceType");
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate 	Assert.nonNullParameter(documentURL, "documentURL");
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 	Assert.nonNullParameter(languageLocale, "language");
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 	Assert.nonNullParameter(version, "version");
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate 	String language = languageLocale.getLanguage();
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 	if (language == null || language.length() <= 0) {
1490Sstevel@tonic-gate 	    throw
1500Sstevel@tonic-gate 		new IllegalArgumentException(
1510Sstevel@tonic-gate 		SLPConfig.getSLPConfig().formatMessage("template_lang_null",
1520Sstevel@tonic-gate 						       new Object[] {
1530Sstevel@tonic-gate 		    documentURL}));
1540Sstevel@tonic-gate 	}
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 	String turl = null;
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 	try {
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 	    turl = findTemplateURL(serviceType,
1610Sstevel@tonic-gate 				   languageLocale,
1620Sstevel@tonic-gate 				   version);
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 	} catch (ServiceLocationException ex) {
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 	    // Ignore if language not supported, it just means there
1670Sstevel@tonic-gate 	    //  isn't any.
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 	    if (ex.getErrorCode() !=
1700Sstevel@tonic-gate 		ServiceLocationException.LANGUAGE_NOT_SUPPORTED) {
1710Sstevel@tonic-gate 		throw ex;
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 	    }
1740Sstevel@tonic-gate 	}
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	// Throw an exception if it exists.
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	if (turl != null) {
1790Sstevel@tonic-gate 	    throw
1800Sstevel@tonic-gate 		new ServiceLocationException(
1810Sstevel@tonic-gate 				ServiceLocationException.INVALID_REGISTRATION,
1820Sstevel@tonic-gate 				"template_already_registered",
1830Sstevel@tonic-gate 				new Object[] {
1840Sstevel@tonic-gate 		    documentURL,
1850Sstevel@tonic-gate 			version,
1860Sstevel@tonic-gate 			languageLocale});
1870Sstevel@tonic-gate 	}
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	// Construct attributes for the registration.
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 	Vector attributes = new Vector();
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 	// Add the service type name.
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	Vector values = new Vector();
1960Sstevel@tonic-gate 	values.addElement(serviceType.toString());
1970Sstevel@tonic-gate 	ServiceLocationAttribute attr =
1980Sstevel@tonic-gate 	    new ServiceLocationAttribute(SERVICE_ATTR_ID, values);
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	attributes.addElement(attr);
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate 	// Add the version.
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	values = new Vector();
2050Sstevel@tonic-gate 	values.addElement(version);
2060Sstevel@tonic-gate 	attr =
2070Sstevel@tonic-gate 	    new ServiceLocationAttribute(VERSION_ATTR_ID, values);
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate 	attributes.addElement(attr);
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 	// Construct a service URL for the template.
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	ServiceURL surl =
2140Sstevel@tonic-gate 	    new ServiceURL(TEMPLATE_SERVICE_TYPE +
2150Sstevel@tonic-gate 			   ":"+
2160Sstevel@tonic-gate 			   documentURL+
2170Sstevel@tonic-gate 			   ";"+
2180Sstevel@tonic-gate 			   SERVICE_ATTR_ID+
2190Sstevel@tonic-gate 			   "="+
2200Sstevel@tonic-gate 			   serviceType+
2210Sstevel@tonic-gate 			   ";"+
2220Sstevel@tonic-gate 			   VERSION_ATTR_ID+
2230Sstevel@tonic-gate 			   "="+
2240Sstevel@tonic-gate 			   version,
2250Sstevel@tonic-gate 			   ServiceURL.LIFETIME_MAXIMUM);
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 	// Do the registration.
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	Advertiser serviceAgent =
2310Sstevel@tonic-gate 	    ServiceLocationManager.getAdvertiser(languageLocale);
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 	if (serviceAgent == null) {
2340Sstevel@tonic-gate 	    throw
2350Sstevel@tonic-gate 		new ServiceLocationException(
2360Sstevel@tonic-gate 				ServiceLocationException.NOT_IMPLEMENTED,
2370Sstevel@tonic-gate 				"no_advertiser",
2380Sstevel@tonic-gate 				new Object[0]);
2390Sstevel@tonic-gate 	}
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 	serviceAgent.register(surl, attributes);
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	// Note that the assumption here is that the URL containing the
2440Sstevel@tonic-gate 	//  path to the template document is written "somehow".
2450Sstevel@tonic-gate 	//  It is up to the client to make sure that the template document
2460Sstevel@tonic-gate 	//  has been written.
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate     }
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate     /**
2510Sstevel@tonic-gate      * Deregister the template for service type.
2520Sstevel@tonic-gate      *
2530Sstevel@tonic-gate      * @param serviceType	Name of service.
2540Sstevel@tonic-gate      * @param <i>languageLocale</i> Language locale of template.
2550Sstevel@tonic-gate      * @param <i>version</i> Version of the template, null for latest.
2560Sstevel@tonic-gate      * @exception ServiceLocationException Thrown if the deregistration
2570Sstevel@tonic-gate      *					  fails.
2580Sstevel@tonic-gate      * @exception IllegalArgumentException Thrown if the parameter is null.
2590Sstevel@tonic-gate      *
2600Sstevel@tonic-gate      */
2610Sstevel@tonic-gate 
deregisterServiceTemplate(ServiceType serviceType, Locale languageLocale, String version)2620Sstevel@tonic-gate     public void deregisterServiceTemplate(ServiceType serviceType,
2630Sstevel@tonic-gate 					  Locale languageLocale,
2640Sstevel@tonic-gate 					  String version)
2650Sstevel@tonic-gate 	throws ServiceLocationException {
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 	// Check the parameter.
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 	Assert.nonNullParameter(serviceType, "serviceType");
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	Assert.nonNullParameter(languageLocale, "languageLocale");
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 	// Get the template document URL for the service.
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	ServiceURL turl = findVersionedURL(serviceType,
2760Sstevel@tonic-gate 					   languageLocale,
2770Sstevel@tonic-gate 					   version);
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 	// If there's no template, then throw an exception.
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	if (turl == null) {
2820Sstevel@tonic-gate 	    throw
2830Sstevel@tonic-gate 		new ServiceLocationException(
2840Sstevel@tonic-gate 				ServiceLocationException.INVALID_REGISTRATION,
2850Sstevel@tonic-gate 				"template_not_registered",
2860Sstevel@tonic-gate 				new Object[] {
2870Sstevel@tonic-gate 		    serviceType,
2880Sstevel@tonic-gate 			version,
2890Sstevel@tonic-gate 			languageLocale});
2900Sstevel@tonic-gate 	}
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 	// Deregister in all scopes.
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	Advertiser serviceAgent =
2950Sstevel@tonic-gate 	    ServiceLocationManager.getAdvertiser(languageLocale);
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	if (serviceAgent == null) {
2980Sstevel@tonic-gate 	    throw
2990Sstevel@tonic-gate 		new ServiceLocationException(
3000Sstevel@tonic-gate 				ServiceLocationException.NOT_IMPLEMENTED,
3010Sstevel@tonic-gate 				"no_advertiser",
3020Sstevel@tonic-gate 				new Object[0]);
3030Sstevel@tonic-gate 	}
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 	// Deregister the service URL.
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	serviceAgent.deregister(turl);
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate     }
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate     /**
3140Sstevel@tonic-gate      * Find the service URL for the service.
3150Sstevel@tonic-gate      *
3160Sstevel@tonic-gate      * @param serviceType		Name of service.
3170Sstevel@tonic-gate      * @param <i>languageLocale</i> Language locale of template.
3180Sstevel@tonic-gate      * @param <i>version</i> Version of the template, null for latest.
3190Sstevel@tonic-gate      * @return ServiceURL for the service template. If the service doesn't
3200Sstevel@tonic-gate      *		exist, returns null.
3210Sstevel@tonic-gate      * @exception ServiceLocationException Error code is
3220Sstevel@tonic-gate      *				    SYSTEM_ERROR
3230Sstevel@tonic-gate      *					   if the scope vector is null or
3240Sstevel@tonic-gate      *					   empty or if more than one
3250Sstevel@tonic-gate      *					   template URL is returned.
3260Sstevel@tonic-gate      * @exception IllegalArgumentException Thrown if any parameters are null.
3270Sstevel@tonic-gate      *
3280Sstevel@tonic-gate      */
3290Sstevel@tonic-gate 
findTemplateURL(ServiceType serviceType, Locale languageLocale, String version)3300Sstevel@tonic-gate     public String findTemplateURL(ServiceType serviceType,
3310Sstevel@tonic-gate 				  Locale languageLocale,
3320Sstevel@tonic-gate 				  String version)
3330Sstevel@tonic-gate 	throws ServiceLocationException {
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	// Check the parameter.
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	Assert.nonNullParameter(serviceType, "serviceType");
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	Assert.nonNullParameter(languageLocale, "languageLocale");
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 	ServiceURL turl = findVersionedURL(serviceType,
3420Sstevel@tonic-gate 					   languageLocale,
3430Sstevel@tonic-gate 					   version);
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 	// If nothing returned, then simply return.
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 	if (turl == null) {
3480Sstevel@tonic-gate 	    return null;
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	}
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	// Form the document URL.
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 	ServiceType type = turl.getServiceType();
3550Sstevel@tonic-gate 	String url = turl.toString();
3560Sstevel@tonic-gate 	String abstractType = type.getAbstractTypeName();
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 	if (!abstractType.equals(TEMPLATE_SERVICE_TYPE)) {
3590Sstevel@tonic-gate 	    throw
3600Sstevel@tonic-gate 		new ServiceLocationException(
3610Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
3620Sstevel@tonic-gate 				"template_url_malformed",
3630Sstevel@tonic-gate 				new Object[] {turl});
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 	}
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	// Parse off the URL path.
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 	int idx = url.indexOf(";"+SERVICE_ATTR_ID+"=");
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	if (idx == -1) {
3720Sstevel@tonic-gate 	    throw
3730Sstevel@tonic-gate 		new ServiceLocationException(
3740Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
3750Sstevel@tonic-gate 				"template_url_malformed",
3760Sstevel@tonic-gate 				new Object[] {turl});
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	}
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	int jdx = TEMPLATE_SERVICE_TYPE.length() + 1; // don't forget :!!!
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	// Return the document URL.
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 	return url.substring(jdx, idx);
3850Sstevel@tonic-gate     }
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate     // Return a URL given a version and language locale.
3880Sstevel@tonic-gate 
findVersionedURL(ServiceType serviceType, Locale languageLocale, String version)3890Sstevel@tonic-gate     private ServiceURL findVersionedURL(ServiceType serviceType,
3900Sstevel@tonic-gate 					Locale languageLocale,
3910Sstevel@tonic-gate 					String version)
3920Sstevel@tonic-gate 	throws ServiceLocationException {
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	// Templates should be registered in all scopes. Look for them
3950Sstevel@tonic-gate 	//  in all.
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	Vector scopes = ServiceLocationManager.findScopes();
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	// Set up query.
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	ServiceLocationEnumeration results = null;
4020Sstevel@tonic-gate 	String query = "(" + SERVICE_ATTR_ID + "=" + serviceType + ")";
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 	if (version != null) {
4050Sstevel@tonic-gate 	    query = query + "(" + VERSION_ATTR_ID + "=" + version + ")";
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 	}
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 	query = "(&" + query + ")";
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	// Get user agent for query.
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 	Locator userAgent =
4140Sstevel@tonic-gate 	    ServiceLocationManager.getLocator(languageLocale);
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 	if (userAgent == null) {
4170Sstevel@tonic-gate 	    throw
4180Sstevel@tonic-gate 		new ServiceLocationException(
4190Sstevel@tonic-gate 				ServiceLocationException.NOT_IMPLEMENTED,
4200Sstevel@tonic-gate 				"no_locator",
4210Sstevel@tonic-gate 				new Object[0]);
4220Sstevel@tonic-gate 	}
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate 	try {
4250Sstevel@tonic-gate 	    ServiceType type = new ServiceType(TEMPLATE_SERVICE_TYPE);
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	    results =
4280Sstevel@tonic-gate 		userAgent.findServices(type,
4290Sstevel@tonic-gate 				       scopes,
4300Sstevel@tonic-gate 				       query);
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	} catch (ServiceLocationException ex) {
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 	    // If language not supported, it just means none there.
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 	    if (ex.getErrorCode() !=
4370Sstevel@tonic-gate 		ServiceLocationException.LANGUAGE_NOT_SUPPORTED) {
4380Sstevel@tonic-gate 		throw ex;
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 	    }
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	}
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	// If nothing came back, then return null.
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	if (!results.hasMoreElements()) {
4470Sstevel@tonic-gate 	    return null;
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 	}
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 	ServiceURL turl = null;
4530Sstevel@tonic-gate 	float highest = (float)-1.0;
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 	// If there's more than one service of this type registered, then
4560Sstevel@tonic-gate 	//  take highest version if version number was null.
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	while (results.hasMoreElements()) {
4590Sstevel@tonic-gate 	    ServiceURL surl = (ServiceURL)results.nextElement();
4600Sstevel@tonic-gate 	    String urlPath = surl.getURLPath();
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 	    if (version == null) {
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate 		// Get the version attribute from the URL.
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 		String token = ";"+VERSION_ATTR_ID+"=";
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 		int idx = urlPath.indexOf(token);
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 		if (idx == -1) { // ignore, there may be more...
4710Sstevel@tonic-gate 		    continue;
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 		}
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 		urlPath =
4760Sstevel@tonic-gate 		    urlPath.substring(idx+token.length(), urlPath.length());
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 		idx = urlPath.indexOf(";");
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 		if (idx == -1) { // ignore, there may be more...
4810Sstevel@tonic-gate 		    continue;
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 		}
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 		String temversion = urlPath.substring(0, idx);
4860Sstevel@tonic-gate 		float current = (float)0.0;
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 		// Convert to float.
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 		try {
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 		    current = Float.valueOf(temversion).floatValue();
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 		} catch (NumberFormatException ex) {
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 		    continue;  // ignore, there may be more...
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 		}
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 		// Identify if this is the highest version number so far.
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 		if (current > highest) {
5030Sstevel@tonic-gate 		    turl = surl;
5040Sstevel@tonic-gate 		}
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 	    } else {
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 		// If we found more than one, may be a problem.
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate 		if (turl != null) {
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 		    throw
5130Sstevel@tonic-gate 			new ServiceLocationException(
5140Sstevel@tonic-gate 				ServiceLocationException.INTERNAL_SYSTEM_ERROR,
5150Sstevel@tonic-gate 				"template_multiple",
5160Sstevel@tonic-gate 				new Object[] {
5170Sstevel@tonic-gate 			    serviceType,
5180Sstevel@tonic-gate 				version,
5190Sstevel@tonic-gate 				languageLocale});
5200Sstevel@tonic-gate 		}
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 		turl = surl;
5230Sstevel@tonic-gate 	    }
5240Sstevel@tonic-gate 	}
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 	return turl;
5270Sstevel@tonic-gate     }
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate     /**
5300Sstevel@tonic-gate      * Create an attribute verifier for the template document URL.
5310Sstevel@tonic-gate      *
5320Sstevel@tonic-gate      * @param documentURL A URL for the template document URL.
5330Sstevel@tonic-gate      * @return An attribute verifier for the service
5340Sstevel@tonic-gate      * @exception ServiceLocationException Throws
5350Sstevel@tonic-gate      *					  PARSE_ERROR
5360Sstevel@tonic-gate      *					  if any syntax errors
5370Sstevel@tonic-gate      *					  are encountered during parsing
5380Sstevel@tonic-gate      *					  of service's template definition.
5390Sstevel@tonic-gate      *					  Throws
5400Sstevel@tonic-gate      *					SYSTEM_ERROR
5410Sstevel@tonic-gate      *					  if URL parsing error occurs.
5420Sstevel@tonic-gate      *					  Throws ServiceLocationException
5430Sstevel@tonic-gate      *					  if any other errors occur.
5440Sstevel@tonic-gate      * @exception IllegalArgumentException Thrown if any parameters are null.
5450Sstevel@tonic-gate      *
5460Sstevel@tonic-gate      */
5470Sstevel@tonic-gate 
attributeVerifier( String documentURL)5480Sstevel@tonic-gate     public ServiceLocationAttributeVerifier attributeVerifier(
5490Sstevel@tonic-gate 							String documentURL)
5500Sstevel@tonic-gate 	throws ServiceLocationException {
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 	// Check the parameter.
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate 	Assert.nonNullParameter(documentURL, "documentURL");
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 	// Create a URL attribute parser to parse the document.
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 	return new URLAttributeVerifier(documentURL);
5590Sstevel@tonic-gate     }
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate }
562