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-2001 by Sun Microsystems, Inc.
230Sstevel@tonic-gate  * All rights reserved.
240Sstevel@tonic-gate  *
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate //  AttributeVerifier.java: An attribute verifier for SLP attributes.
280Sstevel@tonic-gate //  Author:           James Kempf
290Sstevel@tonic-gate //  Created On:       Thu Jun 19 10:51:32 1997
300Sstevel@tonic-gate //  Last Modified By: James Kempf
310Sstevel@tonic-gate //  Last Modified On: Mon Nov  9 10:21:02 1998
320Sstevel@tonic-gate //  Update Count:     200
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 
400Sstevel@tonic-gate /**
410Sstevel@tonic-gate  * The AttributeVerifier class implements the ServiceLocationAttributeVerifier
420Sstevel@tonic-gate  * interface, but without committment to a particular mechanism for
430Sstevel@tonic-gate  * obtaining the template defintion. Subclasses provide the mechanism,
440Sstevel@tonic-gate  * and pass in the template to the parent as a Reader during object
450Sstevel@tonic-gate  * creation. The AttributeVerifier class parses tokens from the Reader and
460Sstevel@tonic-gate  * constructs the attribute descriptor objects describing the attribute. These
470Sstevel@tonic-gate  * are used during verification of the attribute. The AttributeVerifier
480Sstevel@tonic-gate  * and implementations of the attribute descriptors are free to optimize
490Sstevel@tonic-gate  * space utilization by lazily evaluating portions of the attribute
500Sstevel@tonic-gate  * template.
510Sstevel@tonic-gate  *
520Sstevel@tonic-gate  * @author James Kempf
530Sstevel@tonic-gate  *
540Sstevel@tonic-gate  */
550Sstevel@tonic-gate 
560Sstevel@tonic-gate class AttributeVerifier
570Sstevel@tonic-gate     extends Object
580Sstevel@tonic-gate     implements ServiceLocationAttributeVerifier {
590Sstevel@tonic-gate 
600Sstevel@tonic-gate     // Template specific escape.
610Sstevel@tonic-gate 
620Sstevel@tonic-gate     private static final String ESC_HASH = "\\23";
630Sstevel@tonic-gate     private static final String HASH = "#";
640Sstevel@tonic-gate 
650Sstevel@tonic-gate     // Number of template attributes.
660Sstevel@tonic-gate 
670Sstevel@tonic-gate     private static final int TEMPLATE_ATTR_NO = 5;
680Sstevel@tonic-gate 
690Sstevel@tonic-gate     // Bitfields for found template attributes.
700Sstevel@tonic-gate 
710Sstevel@tonic-gate     private static final int SERVICE_MASK = 0x01;
720Sstevel@tonic-gate     private static final int VERSION_MASK = 0x02;
730Sstevel@tonic-gate     private static final int DESCRIPTION_MASK = 0x08;
740Sstevel@tonic-gate     private static final int URL_PATH_RULES_MASK = 0x10;
750Sstevel@tonic-gate 
760Sstevel@tonic-gate     // When all template attribute assignments are found.
770Sstevel@tonic-gate 
780Sstevel@tonic-gate     private static final int TEMPLATE_FOUND = (SERVICE_MASK |
790Sstevel@tonic-gate 					       VERSION_MASK |
800Sstevel@tonic-gate 					       DESCRIPTION_MASK |
810Sstevel@tonic-gate 					       URL_PATH_RULES_MASK);
820Sstevel@tonic-gate 
830Sstevel@tonic-gate     // These are the valid SLP types.
840Sstevel@tonic-gate 
850Sstevel@tonic-gate     private static final String INTEGER_TYPE = "integer";
860Sstevel@tonic-gate     private static final String STRING_TYPE = "string";
870Sstevel@tonic-gate     private static final String BOOLEAN_TYPE = "boolean";
880Sstevel@tonic-gate     private static final String OPAQUE_TYPE = "opaque";
890Sstevel@tonic-gate     private static final String KEYWORD_TYPE = "keyword";
900Sstevel@tonic-gate 
910Sstevel@tonic-gate     // These are the corresponding Java types. Package public so
920Sstevel@tonic-gate     //  others (SLPConfig for example) can get at them.
930Sstevel@tonic-gate 
940Sstevel@tonic-gate     static final String JAVA_STRING_TYPE =
950Sstevel@tonic-gate 	"java.lang.String";
960Sstevel@tonic-gate     static final String JAVA_INTEGER_TYPE =
970Sstevel@tonic-gate 	"java.lang.Integer";
980Sstevel@tonic-gate     static final String JAVA_BOOLEAN_TYPE =
990Sstevel@tonic-gate 	"java.lang.Boolean";
1000Sstevel@tonic-gate     static final String JAVA_OPAQUE_TYPE =
1010Sstevel@tonic-gate 	"[B";
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate     // Tokens for boolean values.
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate     private static final String TRUE_TOKEN = "true";
1060Sstevel@tonic-gate     private static final String FALSE_TOKEN = "false";
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate     // This is the number of flags.
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate     private static final int FLAG_NO = 4;
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate     // These are the flags.
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate     private static final String MULTIPLE_FLAG = "m";
1150Sstevel@tonic-gate     private static final String LITERAL_FLAG = "l";
1160Sstevel@tonic-gate     private static final String EXPLICIT_FLAG = "x";
1170Sstevel@tonic-gate     private static final String OPTIONAL_FLAG = "o";
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate     // These masks help determine whether the flags have been duplicated.
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate     private static final byte MULTIPLE_MASK = 0x01;
1220Sstevel@tonic-gate     private static final byte LITERAL_MASK = 0x02;
1230Sstevel@tonic-gate     private static final byte EXPLICIT_MASK = 0x04;
1240Sstevel@tonic-gate     private static final byte OPTIONAL_MASK = 0x08;
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate     // These are tokens for separator characters.
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate     private static final char TT_COMMA = ',';
1290Sstevel@tonic-gate     private static final char TT_EQUALS = '=';
1300Sstevel@tonic-gate     private static final char TT_FIELD = '#';
1310Sstevel@tonic-gate     private static final char TT_ESCAPE = '\\';
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate     // This token is for checking version number
1340Sstevel@tonic-gate     // attribute assignment.
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate     private static final char TT_PERIOD = '.';
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate     // Radix64 code characters.
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate     private static final char UPPER_START_CODE = 'A';
1410Sstevel@tonic-gate     private static final char UPPER_END_CODE = 'Z';
1420Sstevel@tonic-gate     private static final char LOWER_START_CODE = 'a';
1430Sstevel@tonic-gate     private static final char LOWER_END_CODE = 'z';
1440Sstevel@tonic-gate     private static final char NUMBER_START_CODE = '0';
1450Sstevel@tonic-gate     private static final char NUMBER_END_CODE = '9';
1460Sstevel@tonic-gate     private static final char EXTRA_CODE1 = '+';
1470Sstevel@tonic-gate     private static final char EXTRA_CODE2 = '/';
1480Sstevel@tonic-gate     private static final char PAD_CODE = '=';
1490Sstevel@tonic-gate     private static final char LENGTH_SEPERATOR = ':';
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate     // The SLP service type of this template.
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate     private ServiceType serviceType;
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate     // The template's language locale.
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate     private Locale locale;
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate     // The template's version.
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate     private String version;
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate     // The template's URL syntax.
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate     private String URLSyntax;
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate     // The template's description.
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate     private String description;
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate     // The attribute descriptors.
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate     private Hashtable attributeDescriptors = new Hashtable();
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate     //
1760Sstevel@tonic-gate     // Constructors.
1770Sstevel@tonic-gate 
AttributeVerifier()1780Sstevel@tonic-gate     AttributeVerifier() {
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate     }
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate     // Initialize the attribute verifier with a reader. Subclasses or clients
1830Sstevel@tonic-gate     // pass in a Reader on the template that is used for parsing. This
1840Sstevel@tonic-gate     // method is used when the template includes the template attributes
1850Sstevel@tonic-gate     // and URL rules.
1860Sstevel@tonic-gate 
initialize(Reader r)1870Sstevel@tonic-gate     void initialize(Reader r) throws ServiceLocationException {
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	// Use a StreamTokenizer to parse.
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 	StreamTokenizer tk = new StreamTokenizer(r);
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 	// Initialize tokenizer for parsing main.
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	initFieldChar(tk);
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 	// Now parse the attribute template, including template attributes.
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 	parseTemplate(tk);
2000Sstevel@tonic-gate     }
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate     // Initialize with this method when no template attributes are involved.
2030Sstevel@tonic-gate 
initializeAttributesOnly(Reader r)2040Sstevel@tonic-gate     void initializeAttributesOnly(Reader r)
2050Sstevel@tonic-gate 	throws ServiceLocationException {
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 	// Use a StreamTokenizer to parse.
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate 	StreamTokenizer tk = new StreamTokenizer(r);
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 	// Initialize tokenizer for parsing main.
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	initFieldChar(tk);
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	// Now parse the attribute templates, but no template attributes.
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 	parseAttributes(tk);
2180Sstevel@tonic-gate     }
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate     //
2210Sstevel@tonic-gate     // ServiceLocationAttributeVerifier interface implementation.
2220Sstevel@tonic-gate     //
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate     /**
2250Sstevel@tonic-gate      * Returns the SLP service type for which this is the verifier.
2260Sstevel@tonic-gate      *
2270Sstevel@tonic-gate      * @return The SLP service type name.
2280Sstevel@tonic-gate      */
2290Sstevel@tonic-gate 
getServiceType()2300Sstevel@tonic-gate     public ServiceType getServiceType() {
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 	return serviceType;
2330Sstevel@tonic-gate     }
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate     /**
2360Sstevel@tonic-gate      * Returns the SLP language locale of this is the verifier.
2370Sstevel@tonic-gate      *
2380Sstevel@tonic-gate      * @return The SLP language locale.
2390Sstevel@tonic-gate      */
2400Sstevel@tonic-gate 
getLocale()2410Sstevel@tonic-gate     public Locale getLocale() {
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	return locale;
2440Sstevel@tonic-gate     }
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate     /**
2470Sstevel@tonic-gate      * Returns the SLP version of this is the verifier.
2480Sstevel@tonic-gate      *
2490Sstevel@tonic-gate      * @return The SLP version.
2500Sstevel@tonic-gate      */
2510Sstevel@tonic-gate 
getVersion()2520Sstevel@tonic-gate     public String getVersion() {
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 	return version;
2550Sstevel@tonic-gate     }
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate     /**
2580Sstevel@tonic-gate      * Returns the SLP URL syntax of this is the verifier.
2590Sstevel@tonic-gate      *
2600Sstevel@tonic-gate      * @return The SLP URL syntax.
2610Sstevel@tonic-gate      */
2620Sstevel@tonic-gate 
getURLSyntax()2630Sstevel@tonic-gate     public String getURLSyntax() {
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 	return URLSyntax;
2660Sstevel@tonic-gate     }
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate     /**
2690Sstevel@tonic-gate      * Returns the SLP description of this is the verifier.
2700Sstevel@tonic-gate      *
2710Sstevel@tonic-gate      * @return The SLP description.
2720Sstevel@tonic-gate      */
2730Sstevel@tonic-gate 
getDescription()2740Sstevel@tonic-gate     public String getDescription() {
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 	return description;
2770Sstevel@tonic-gate     }
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate     /**
2800Sstevel@tonic-gate      * Returns the ServiceLocationAttributeDescriptor object for the
2810Sstevel@tonic-gate      * attribute having the named id. IF no such attribute exists in the
2820Sstevel@tonic-gate      * template, returns null. This method is primarily for GUI tools to
2830Sstevel@tonic-gate      * display attribute information. Programmatic verification of attributes
2840Sstevel@tonic-gate      * should use the verifyAttribute() method.
2850Sstevel@tonic-gate      *
2860Sstevel@tonic-gate      * @param attrId Id of attribute to return.
2870Sstevel@tonic-gate      * @return The ServiceLocationAttributeDescriptor object corresponding
2880Sstevel@tonic-gate      * 	     to the parameter, or null if none.
2890Sstevel@tonic-gate      */
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate     public ServiceLocationAttributeDescriptor
getAttributeDescriptor(String attrId)2920Sstevel@tonic-gate 	getAttributeDescriptor(String attrId) {
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	return
2950Sstevel@tonic-gate 	    (ServiceLocationAttributeDescriptor)
2960Sstevel@tonic-gate 	    attributeDescriptors.get(attrId.toLowerCase());
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate     }
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate     /**
3010Sstevel@tonic-gate      * Returns an Enumeration of
3020Sstevel@tonic-gate      * ServiceLocationAttributeDescriptors for the template. This method
3030Sstevel@tonic-gate      * is primarily for GUI tools to display attribute information.
3040Sstevel@tonic-gate      * Programmatic verification of attributes should use the
3050Sstevel@tonic-gate      * verifyAttribute() method. Note that small memory implementations
3060Sstevel@tonic-gate      * may want to implement the Enumeration so that attributes are
3070Sstevel@tonic-gate      * parsed on demand rather than at creation time.
3080Sstevel@tonic-gate      *
3090Sstevel@tonic-gate      * @return A Dictionary with attribute id's as the keys and
3100Sstevel@tonic-gate      *	      ServiceLocationAttributeDescriptor objects for the
3110Sstevel@tonic-gate      *	      attributes as the values.
3120Sstevel@tonic-gate      */
3130Sstevel@tonic-gate 
getAttributeDescriptors()3140Sstevel@tonic-gate     public Enumeration getAttributeDescriptors() {
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	return ((Hashtable)attributeDescriptors.clone()).elements();
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate     }
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate     /**
3210Sstevel@tonic-gate      * Verify that the attribute parameter is a valid SLP attribute.
3220Sstevel@tonic-gate      *
3230Sstevel@tonic-gate      * @param attribute The ServiceLocationAttribute to be verified.
3240Sstevel@tonic-gate      */
3250Sstevel@tonic-gate 
verifyAttribute(ServiceLocationAttribute attribute)3260Sstevel@tonic-gate     public void verifyAttribute(ServiceLocationAttribute attribute)
3270Sstevel@tonic-gate 	throws ServiceLocationException {
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 	String id = attribute.getId().toLowerCase();
3300Sstevel@tonic-gate 	ServiceLocationAttributeDescriptor des =
3310Sstevel@tonic-gate 	    (ServiceLocationAttributeDescriptor)attributeDescriptors.get(id);
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	if (des == null) {
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	    throw
3360Sstevel@tonic-gate 		new ServiceLocationException(
3370Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
3380Sstevel@tonic-gate 				"template_no_attribute",
3390Sstevel@tonic-gate 				new Object[] { id });
3400Sstevel@tonic-gate 	}
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 	String type = des.getValueType();
3440Sstevel@tonic-gate 	Vector vals = attribute.getValues();
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 	// If keyword, check that no values were specified.
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	if (des.getIsKeyword()) {
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	    if (vals != null) {
3510Sstevel@tonic-gate 		throw
3520Sstevel@tonic-gate 		    new ServiceLocationException(
3530Sstevel@tonic-gate 					 ServiceLocationException.PARSE_ERROR,
3540Sstevel@tonic-gate 					 "template_not_null",
3550Sstevel@tonic-gate 					 new Object[] { id });
3560Sstevel@tonic-gate 	    }
3570Sstevel@tonic-gate 	} else {
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 	    int i, n;
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 	    // Check that a values vector exists, and, if the attribute is
3620Sstevel@tonic-gate 	    //  not multivalued, only one element is in it.
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 	    if (vals == null) {
3650Sstevel@tonic-gate 		throw
3660Sstevel@tonic-gate 		    new ServiceLocationException(
3670Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
3680Sstevel@tonic-gate 				"template_null",
3690Sstevel@tonic-gate 				new Object[] { id });
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	    }
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 	    n = vals.size();
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate 	    if (n > 1 && !des.getIsMultivalued()) {
3760Sstevel@tonic-gate 		throw
3770Sstevel@tonic-gate 		    new ServiceLocationException(
3780Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
3790Sstevel@tonic-gate 				"template_not_multi",
3800Sstevel@tonic-gate 				new Object[] { id });
3810Sstevel@tonic-gate 	    }
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 	    // Get allowed values.
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 	    Vector av = null;
3860Sstevel@tonic-gate 	    Enumeration en = des.getAllowedValues();
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 	    if (en.hasMoreElements()) {
3890Sstevel@tonic-gate 		av = new Vector();
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 		while (en.hasMoreElements()) {
3920Sstevel@tonic-gate 		    Object v = en.nextElement();
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 		    // Lower case if string, convert to Opaque if byte array.
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 		    if (type.equals(JAVA_STRING_TYPE)) {
3970Sstevel@tonic-gate 			v = ((String)v).toLowerCase();
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 		    } else if (type.equals(JAVA_OPAQUE_TYPE)) {
4000Sstevel@tonic-gate 			v = new Opaque((byte[])v);
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 		    }
4030Sstevel@tonic-gate 		    av.addElement(v);
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate 		}
4060Sstevel@tonic-gate 	    }
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	    // Check that the types of the values vector match the attribute
4090Sstevel@tonic-gate 	    //  type. Also, if any allowed values, that attribute values
4100Sstevel@tonic-gate 	    //  match.
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	    String attTypeName = des.getValueType();
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	    for (i = 0; i < n; i++) {
4150Sstevel@tonic-gate 		Object val = vals.elementAt(i);
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 		String typeName = val.getClass().getName();
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 		if (!typeName.equals(attTypeName)) {
4200Sstevel@tonic-gate 		    throw
4210Sstevel@tonic-gate 			new ServiceLocationException(
4220Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
4230Sstevel@tonic-gate 				"template_type_mismatch",
4240Sstevel@tonic-gate 				new Object[] { id, typeName, attTypeName });
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 		}
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 		// Convert value for comparison, if necessary.
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 		if (type.equals(JAVA_STRING_TYPE)) {
4310Sstevel@tonic-gate 		    val = ((String)val).toLowerCase();
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 		} else if (type.equals(JAVA_OPAQUE_TYPE)) {
4340Sstevel@tonic-gate 		    val = new Opaque((byte[])val);
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 		}
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 		if (av != null && !av.contains(val)) {
4390Sstevel@tonic-gate 		    throw
4400Sstevel@tonic-gate 			new ServiceLocationException(
4410Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
4420Sstevel@tonic-gate 				"template_not_allowed_value",
4430Sstevel@tonic-gate 				new Object[] {id, val});
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 		}
4460Sstevel@tonic-gate 	    }
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 	}
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	// No way to verify `X' because that's a search property. We
4510Sstevel@tonic-gate 	//  must verify `O' in the context of an attribute set.
4520Sstevel@tonic-gate     }
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate     /**
4550Sstevel@tonic-gate      * Verify that the set of registration attributes matches the
4560Sstevel@tonic-gate      * required attributes for the service.
4570Sstevel@tonic-gate      *
4580Sstevel@tonic-gate      * @param attributeVector A Vector of ServiceLocationAttribute objects
4590Sstevel@tonic-gate      *			     for the registration.
4600Sstevel@tonic-gate      * @exception ServiceLocationException Thrown if the
4610Sstevel@tonic-gate      *		 attribute set is not valid. The message contains information
4620Sstevel@tonic-gate      *		 on the attribute name and problem.
4630Sstevel@tonic-gate      */
4640Sstevel@tonic-gate 
verifyRegistration(Vector attributeVector)4650Sstevel@tonic-gate     public void verifyRegistration(Vector attributeVector)
4660Sstevel@tonic-gate 	throws ServiceLocationException {
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 	Assert.nonNullParameter(attributeVector, "attributeVector");
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 	if (attributeVector.size() <= 0) {
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	    // Check whether any attributes are required. If so, then
4740Sstevel@tonic-gate 	    // there's an error.
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 	    Enumeration en = attributeDescriptors.elements();
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	    while (en.hasMoreElements()) {
4790Sstevel@tonic-gate 		ServiceLocationAttributeDescriptor attDesc =
4800Sstevel@tonic-gate 		    (ServiceLocationAttributeDescriptor)en.nextElement();
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 		if (!attDesc.getIsOptional()) {
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 		    throw
4850Sstevel@tonic-gate 			new ServiceLocationException(
4860Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
4870Sstevel@tonic-gate 				"template_missing_required",
4880Sstevel@tonic-gate 				new Object[] { attDesc.getId() });
4890Sstevel@tonic-gate 		}
4900Sstevel@tonic-gate 	    }
4910Sstevel@tonic-gate 	} else {
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	    // Construct a hashtable of incoming objects, verifying them
4940Sstevel@tonic-gate 	    // while doing so.
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 	    int i, n = attributeVector.size();
4970Sstevel@tonic-gate 	    Hashtable incoming = new Hashtable();
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 	    for (i = 0; i < n; i++) {
5000Sstevel@tonic-gate 		ServiceLocationAttribute attribute =
5010Sstevel@tonic-gate 		    (ServiceLocationAttribute)attributeVector.elementAt(i);
5020Sstevel@tonic-gate 		String id = attribute.getId().toLowerCase();
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 		// If we already have it, signal a duplicate.
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 		if (incoming.get(id) != null) {
5070Sstevel@tonic-gate 		    throw
5080Sstevel@tonic-gate 			new ServiceLocationException(
5090Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
5100Sstevel@tonic-gate 				"template_dup",
5110Sstevel@tonic-gate 				new Object[] { attribute.getId() });
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 		}
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 		verifyAttribute(attribute);
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate 		incoming.put(id, attribute);
5180Sstevel@tonic-gate 	    }
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 	    // Now check that all required attributes are present.
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 	    Enumeration en = attributeDescriptors.elements();
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 	    while (en.hasMoreElements()) {
5250Sstevel@tonic-gate 		ServiceLocationAttributeDescriptor attDesc =
5260Sstevel@tonic-gate 		    (ServiceLocationAttributeDescriptor)en.nextElement();
5270Sstevel@tonic-gate 		String attrId = attDesc.getId();
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 		if (!attDesc.getIsOptional() &&
5300Sstevel@tonic-gate 		    incoming.get(attrId.toLowerCase()) == null) {
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate 		    throw
5330Sstevel@tonic-gate 			new ServiceLocationException(
5340Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
5350Sstevel@tonic-gate 				"template_missing_required",
5360Sstevel@tonic-gate 				new Object[] { attrId });
5370Sstevel@tonic-gate 		}
5380Sstevel@tonic-gate 	    }
5390Sstevel@tonic-gate 	}
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate     }
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate     //
5440Sstevel@tonic-gate     // Private implementation. This is the template attribute parser.
5450Sstevel@tonic-gate     //
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate     //
5480Sstevel@tonic-gate     // Tokenizer initializers.
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate     // Base initialization. Resets syntax tables, sets up EOL parsing,
5510Sstevel@tonic-gate     //  and makes word case significant.
5520Sstevel@tonic-gate 
initForBase(StreamTokenizer tk)5530Sstevel@tonic-gate     private void initForBase(StreamTokenizer tk) {
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 	// Each part of an attribute production must specify which
5560Sstevel@tonic-gate 	//  characters belong to words.
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 	tk.resetSyntax();
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate 	// Note that we have to make EOL be whitespace even if significant
5610Sstevel@tonic-gate 	//  because otherwise the line number won't be correctly incremented.
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 	tk.whitespaceChars((int)'\n', (int)'\n');
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 	// Don't lower case tokens.
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 	tk.lowerCaseMode(false);
5680Sstevel@tonic-gate     }
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate     // Initialize those token characters that appear in all
5710Sstevel@tonic-gate     //  productions.
5720Sstevel@tonic-gate 
initCommonToken(StreamTokenizer tk)5730Sstevel@tonic-gate     private void initCommonToken(StreamTokenizer tk) {
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 	// These characters are recognized as parts of tokens.
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 	tk.wordChars((int)'A', (int)'Z');
5780Sstevel@tonic-gate 	tk.wordChars((int)'a', (int)'z');
5790Sstevel@tonic-gate 	tk.wordChars((int)'0', (int)'9');
5800Sstevel@tonic-gate 	tk.wordChars((int)'&', (int)'&');
5810Sstevel@tonic-gate 	tk.wordChars((int)'*', (int)'*');
5820Sstevel@tonic-gate 	tk.wordChars((int)':', (int)':');
5830Sstevel@tonic-gate 	tk.wordChars((int)'-', (int)'-');
5840Sstevel@tonic-gate 	tk.wordChars((int)'_', (int)'_');
5850Sstevel@tonic-gate 	tk.wordChars((int)'$', (int)'$');
5860Sstevel@tonic-gate 	tk.wordChars((int)'+', (int)'+');
5870Sstevel@tonic-gate 	tk.wordChars((int)'@', (int)'@');
5880Sstevel@tonic-gate 	tk.wordChars((int)'.', (int)'.');
5890Sstevel@tonic-gate 	tk.wordChars((int)'|', (int)'|');
5900Sstevel@tonic-gate 	tk.wordChars((int)'<', (int)'<');
5910Sstevel@tonic-gate 	tk.wordChars((int)'>', (int)'>');
5920Sstevel@tonic-gate 	tk.wordChars((int)'~', (int)'~');
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate     }
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate     // Initialize tokenizer for parsing attribute name,
5970Sstevel@tonic-gate     // attribute type and flags,
5980Sstevel@tonic-gate     // and for boolean initializer lists.
5990Sstevel@tonic-gate 
initIdChar(StreamTokenizer tk)6000Sstevel@tonic-gate     private void initIdChar(StreamTokenizer tk) {
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 	initForBase(tk);
6030Sstevel@tonic-gate 	initCommonToken(tk);
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 	// Need backslash for escaping.
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 	tk.wordChars((int)'\\', (int)'\\');
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	// Attribute id, Type, flags, and boolean initialzers
6100Sstevel@tonic-gate 	//  all ignore white space.
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate 	tk.whitespaceChars((int)' ', (int)' ');
6130Sstevel@tonic-gate 	tk.whitespaceChars((int)'\t', (int)'\t');
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 	// Attribute part won't view newline as being significant.
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 	tk.eolIsSignificant(false);
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 	// Case is not folded.
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 	tk.lowerCaseMode(false);
6220Sstevel@tonic-gate     }
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate     // Initialize tokenizer for parsing service type name.
6250Sstevel@tonic-gate     //  need to restrict characters.
6260Sstevel@tonic-gate 
initSchemeIdChar(StreamTokenizer tk)6270Sstevel@tonic-gate     private void initSchemeIdChar(StreamTokenizer tk) {
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 	initForBase(tk);
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	tk.wordChars((int)'A', (int)'Z');
6320Sstevel@tonic-gate 	tk.wordChars((int)'a', (int)'z');
6330Sstevel@tonic-gate 	tk.wordChars((int)'0', (int)'9');
6340Sstevel@tonic-gate 	tk.wordChars((int)'-', (int)'-');
6350Sstevel@tonic-gate 	tk.wordChars((int)'+', (int)'+');
6360Sstevel@tonic-gate 	tk.wordChars((int)'.', (int)'.');  // allows naming authority.
6370Sstevel@tonic-gate 	tk.wordChars((int)':', (int)':');  // for abstract and concrete type.
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 	// Scheme name, type, flags, and boolean initialzers
6400Sstevel@tonic-gate 	//  all ignore white space.
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 	tk.whitespaceChars((int)' ', (int)' ');
6430Sstevel@tonic-gate 	tk.whitespaceChars((int)'\t', (int)'\t');
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 	// Scheme part won't view newline as being significant.
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 	tk.eolIsSignificant(false);
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate 	// Case is not folded.
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 	tk.lowerCaseMode(false);
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate     }
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate     // Initialize tokenizer for string list parsing.
6560Sstevel@tonic-gate     //  Everything except '#' and ',' is recognized.
6570Sstevel@tonic-gate     //  Note that whitespace is significant, but
6580Sstevel@tonic-gate     //  EOL is ignored.
6590Sstevel@tonic-gate 
initStringItemChar(StreamTokenizer tk)6600Sstevel@tonic-gate     private void initStringItemChar(StreamTokenizer tk) {
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 	initForBase(tk);
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 	tk.wordChars((int)'\t', (int)'\t');
6650Sstevel@tonic-gate 	tk.wordChars((int)' ', (int)'"');
6660Sstevel@tonic-gate 	// '#' goes here
6670Sstevel@tonic-gate 	tk.wordChars((int)'$', (int)'+');
6680Sstevel@tonic-gate 	// ',' goes here
6690Sstevel@tonic-gate 	tk.wordChars((int)'-', (int)'/');
6700Sstevel@tonic-gate 	tk.wordChars((int)'0', (int)'9');
6710Sstevel@tonic-gate 	tk.wordChars((int)':', (int)':');
6720Sstevel@tonic-gate 	// ';' goes here
6730Sstevel@tonic-gate 	tk.wordChars((int)'<', (int)'@');
6740Sstevel@tonic-gate 	tk.wordChars((int)'A', (int)'Z');
6750Sstevel@tonic-gate 	tk.wordChars((int)'[', (int)'`');
6760Sstevel@tonic-gate 	tk.wordChars((int)'a', (int)'z');
6770Sstevel@tonic-gate 	tk.wordChars((int)'{', (int)'~');
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 	// '%' is also reserved, but it is postprocessed
6800Sstevel@tonic-gate 	// after the string is collected.
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 	// Parse by lines to check when we've reached the end of the list.
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 	tk.whitespaceChars((int)'\r', (int)'\r');
6850Sstevel@tonic-gate 	tk.whitespaceChars((int)'\n', (int)'\n');
6860Sstevel@tonic-gate 	tk.eolIsSignificant(true);
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate     }
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate     // Initialize tokenizer for integer list parsing.
6910Sstevel@tonic-gate 
initIntItemChar(StreamTokenizer tk)6920Sstevel@tonic-gate     private void initIntItemChar(StreamTokenizer tk) {
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate 	initForBase(tk);
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate 	tk.wordChars((int)'0', (int)'9');
6970Sstevel@tonic-gate 	tk.wordChars((int)'-', (int)'-');
6980Sstevel@tonic-gate 	tk.wordChars((int)'+', (int)'+');
6990Sstevel@tonic-gate 
7000Sstevel@tonic-gate 	// Integer value list parsing ignores white space.
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 	tk.whitespaceChars((int)' ', (int)' ');
7030Sstevel@tonic-gate 	tk.whitespaceChars((int)'\t', (int)'\t');
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate 	// Parse by lines so we can find the end.
7060Sstevel@tonic-gate 
7070Sstevel@tonic-gate 	tk.whitespaceChars((int)'\r', (int)'\r');
7080Sstevel@tonic-gate 	tk.whitespaceChars((int)'\n', (int)'\n');
7090Sstevel@tonic-gate 	tk.eolIsSignificant(true);
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate     }
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate     // Boolean lists have same item syntax as scheme char.
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate     // Initialize main production parsing. The only
7160Sstevel@tonic-gate     //  significant token character is <NL> because
7170Sstevel@tonic-gate     //  parsing is done on a line-oriented basis.
7180Sstevel@tonic-gate 
initFieldChar(StreamTokenizer tk)7190Sstevel@tonic-gate     private void initFieldChar(StreamTokenizer tk) {
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate 	initForBase(tk);
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate 	tk.wordChars((int)'\t', (int)'\t');
7240Sstevel@tonic-gate 	tk.wordChars((int)' ', (int)'/');
7250Sstevel@tonic-gate 	tk.wordChars((int)'0', (int)'9');
7260Sstevel@tonic-gate 	tk.wordChars((int)':', (int)'@');
7270Sstevel@tonic-gate 	tk.wordChars((int)'A', (int)'Z');
7280Sstevel@tonic-gate 	tk.wordChars((int)'[', (int)'`');
7290Sstevel@tonic-gate 	tk.wordChars((int)'a', (int)'z');
7300Sstevel@tonic-gate 	tk.wordChars((int)'{', (int)'~');
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 	tk.whitespaceChars((int)'\r', (int)'\r');
7330Sstevel@tonic-gate 	tk.whitespaceChars((int)'\n', (int)'\n');
7340Sstevel@tonic-gate 	tk.eolIsSignificant(true);
7350Sstevel@tonic-gate     }
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate     //
7380Sstevel@tonic-gate     // Parsing methods.
7390Sstevel@tonic-gate     //
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate     // Parse a template from the tokenizer.
7420Sstevel@tonic-gate 
parseTemplate(StreamTokenizer tk)7430Sstevel@tonic-gate     private void parseTemplate(StreamTokenizer tk)
7440Sstevel@tonic-gate 	throws ServiceLocationException {
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 	// First parse past the template attributes.
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate 	parseTemplateAttributes(tk);
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 	// Finally, parse the attributes.
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 	parseAttributes(tk);
7530Sstevel@tonic-gate 
7540Sstevel@tonic-gate     }
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate     // Parse the template attributes from the tokenizer.
7570Sstevel@tonic-gate 
parseTemplateAttributes(StreamTokenizer tk)7580Sstevel@tonic-gate     private void parseTemplateAttributes(StreamTokenizer tk)
7590Sstevel@tonic-gate 	throws ServiceLocationException {
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 	int found = 0;
7620Sstevel@tonic-gate 
7630Sstevel@tonic-gate 	// Parse each of the template attributes. Note that we are parsing
7640Sstevel@tonic-gate 	//  the attribute value assignments, not definitions.
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 	try {
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 	    do {
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 		found = found | parseTemplateAttribute(tk, found);
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate 	    } while (found != TEMPLATE_FOUND);
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate 	} catch (IOException ex) {
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 	    throw
7770Sstevel@tonic-gate 		new ServiceLocationException(
7780Sstevel@tonic-gate 				ServiceLocationException.INTERNAL_SYSTEM_ERROR,
7790Sstevel@tonic-gate 				"template_io_error",
7800Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 	}
7830Sstevel@tonic-gate     }
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate     // Parse a template attribute.
7860Sstevel@tonic-gate 
parseTemplateAttribute(StreamTokenizer tk, int found)7870Sstevel@tonic-gate     private int parseTemplateAttribute(StreamTokenizer tk, int found)
7880Sstevel@tonic-gate 	throws ServiceLocationException, IOException {
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 	// Get line including id and equals.
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 	int tt = tk.nextToken();
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate 	if (tt != StreamTokenizer.TT_WORD) {
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 	    throw
7970Sstevel@tonic-gate 		new ServiceLocationException(
7980Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
7990Sstevel@tonic-gate 				"template_assign_error",
8000Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
8010Sstevel@tonic-gate 	}
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 	// Get tokenizer for id and potential value line.
8040Sstevel@tonic-gate 
8050Sstevel@tonic-gate 	StringReader rdr = new StringReader(tk.sval);
8060Sstevel@tonic-gate 	StreamTokenizer stk = new StreamTokenizer(rdr);
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 	initIdChar(stk);
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate 	// Make sure newline is there.
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 	if ((tt = tk.nextToken()) == StreamTokenizer.TT_EOF) {
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate 	    throw
8150Sstevel@tonic-gate 		new ServiceLocationException(
8160Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
8170Sstevel@tonic-gate 				"template_end_error",
8180Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 	}
8210Sstevel@tonic-gate 
8220Sstevel@tonic-gate 	if (tt != StreamTokenizer.TT_EOL) {
8230Sstevel@tonic-gate 
8240Sstevel@tonic-gate 	    throw
8250Sstevel@tonic-gate 		new ServiceLocationException(
8260Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
8270Sstevel@tonic-gate 				"template_unk_token",
8280Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 	}
8310Sstevel@tonic-gate 
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 	// Parse off id.
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 	if ((tt = stk.nextToken()) != StreamTokenizer.TT_WORD) {
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 	    throw
8380Sstevel@tonic-gate 		new ServiceLocationException(
8390Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
8400Sstevel@tonic-gate 				"template_missing_id",
8410Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
8420Sstevel@tonic-gate 	}
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate 	String id = stk.sval;
8450Sstevel@tonic-gate 	boolean duplicate = false;
8460Sstevel@tonic-gate 	int mask = 0;
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 	// Check for the equals.
8490Sstevel@tonic-gate 
8500Sstevel@tonic-gate 	if ((tt = stk.nextToken()) != TT_EQUALS) {
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 	    throw
8530Sstevel@tonic-gate 		new ServiceLocationException(
8540Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
8550Sstevel@tonic-gate 				"template_missing_eq ",
8560Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate 	}
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate 	// Depending on the id, parse the rest.
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate 	if (id.equalsIgnoreCase(SLPTemplateRegistry.SERVICE_ATTR_ID)) {
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 	    if ((found & SERVICE_MASK) == 0) {
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 		// Just need to parse off the service type.
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate 		if ((tt = stk.nextToken()) != StreamTokenizer.TT_WORD) {
8690Sstevel@tonic-gate 		    throw
8700Sstevel@tonic-gate 			new ServiceLocationException(
8710Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
8720Sstevel@tonic-gate 				"template_srv_type_err",
8730Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
8740Sstevel@tonic-gate 		}
8750Sstevel@tonic-gate 
8760Sstevel@tonic-gate 		// Check for characters which are not alphanumerics, + and -.
8770Sstevel@tonic-gate 		//  Service type names are more heavily restricted.
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate 		StreamTokenizer sttk =
8800Sstevel@tonic-gate 		    new StreamTokenizer(new StringReader(stk.sval));
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 		initSchemeIdChar(sttk);
8830Sstevel@tonic-gate 
8840Sstevel@tonic-gate 		if (sttk.nextToken() != StreamTokenizer.TT_WORD ||
8850Sstevel@tonic-gate 		    !stk.sval.equals(sttk.sval)) {
8860Sstevel@tonic-gate 		    throw
8870Sstevel@tonic-gate 			new ServiceLocationException(
8880Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
8890Sstevel@tonic-gate 				"template_srv_type_err",
8900Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate 		}
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 		// Need to prefix with "serivce:".
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate 		String typeName = sttk.sval;
8970Sstevel@tonic-gate 
8980Sstevel@tonic-gate 		if (!typeName.startsWith(Defaults.SERVICE_PREFIX+":")) {
8990Sstevel@tonic-gate 		    typeName = Defaults.SERVICE_PREFIX+":"+typeName;
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 		}
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 		// Set service type instance variable.
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate 		serviceType = new ServiceType(typeName);
9060Sstevel@tonic-gate 
9070Sstevel@tonic-gate 		// Check for extra stuff.
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 		if ((tt = stk.nextToken()) != StreamTokenizer.TT_EOF) {
9100Sstevel@tonic-gate 		    throw
9110Sstevel@tonic-gate 			new ServiceLocationException(
9120Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
9130Sstevel@tonic-gate 				"template_srv_type_err",
9140Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
9150Sstevel@tonic-gate 		}
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate 		mask = SERVICE_MASK;
9180Sstevel@tonic-gate 	    } else {
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 		duplicate = true;
9210Sstevel@tonic-gate 	    }
9220Sstevel@tonic-gate 	} else if (id.equalsIgnoreCase(SLPTemplateRegistry.VERSION_ATTR_ID)) {
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate 	    if ((found & VERSION_MASK) == 0) {
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate 		// Just need to parse off the version number.
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate 		if ((tt = stk.nextToken()) != StreamTokenizer.TT_WORD) {
9290Sstevel@tonic-gate 		    throw
9300Sstevel@tonic-gate 			new ServiceLocationException(
9310Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
9320Sstevel@tonic-gate 				"template_vers_err",
9330Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
9340Sstevel@tonic-gate 		}
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 		// Make sure it's a valid version number.
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate 		String version = stk.sval;
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 		if (version.indexOf(TT_PERIOD) == -1) {
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate 		    throw
9430Sstevel@tonic-gate 			new ServiceLocationException(
9440Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
9450Sstevel@tonic-gate 				"template_vers_mssing",
9460Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate 		}
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 		try {
9510Sstevel@tonic-gate 
9520Sstevel@tonic-gate 		    new Float(version);
9530Sstevel@tonic-gate 		} catch (NumberFormatException ex) {
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 		    throw
9560Sstevel@tonic-gate 			new ServiceLocationException(
9570Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
9580Sstevel@tonic-gate 				"template_vers_err",
9590Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
9600Sstevel@tonic-gate 
9610Sstevel@tonic-gate 		}
9620Sstevel@tonic-gate 
9630Sstevel@tonic-gate 		this.version = version;
9640Sstevel@tonic-gate 
9650Sstevel@tonic-gate 		// Check for extra stuff.
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate 		if ((tt = stk.nextToken()) != StreamTokenizer.TT_EOF) {
9680Sstevel@tonic-gate 		    throw
9690Sstevel@tonic-gate 			new ServiceLocationException(
9700Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
9710Sstevel@tonic-gate 				"template_vers_err",
9720Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
9730Sstevel@tonic-gate 		}
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate 		mask = VERSION_MASK;
9760Sstevel@tonic-gate 	    } else {
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 		duplicate = true;
9790Sstevel@tonic-gate 	    }
9800Sstevel@tonic-gate 	} else if (id.equalsIgnoreCase(
9810Sstevel@tonic-gate 				SLPTemplateRegistry.DESCRIPTION_ATTR_ID)) {
9820Sstevel@tonic-gate 
9830Sstevel@tonic-gate 	    // Make sure there is nothing else on that line.
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate 	    if (stk.nextToken() != StreamTokenizer.TT_EOF) {
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate 		throw
9880Sstevel@tonic-gate 		    new ServiceLocationException(
9890Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
9900Sstevel@tonic-gate 				"template_attr_syntax",
9910Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
9920Sstevel@tonic-gate 	    }
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate 	    if ((found & DESCRIPTION_MASK) == 0) {
9950Sstevel@tonic-gate 
9960Sstevel@tonic-gate 		// Need to continue parsing help text until we reach a blank
9970Sstevel@tonic-gate 		// line.
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate 		String helpText = "";
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate 		do {
10020Sstevel@tonic-gate 		    int ptt = tt;
10030Sstevel@tonic-gate 		    tt = tk.nextToken();
10040Sstevel@tonic-gate 
10050Sstevel@tonic-gate 		    if (tt == StreamTokenizer.TT_WORD) {
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate 			helpText = helpText + tk.sval + "\n";
10080Sstevel@tonic-gate 
10090Sstevel@tonic-gate 		    } else if (tt == StreamTokenizer.TT_EOL) {
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate 			// If previous token was end of line, quit.
10120Sstevel@tonic-gate 
10130Sstevel@tonic-gate 			if (ptt == StreamTokenizer.TT_EOL) {
10140Sstevel@tonic-gate 
10150Sstevel@tonic-gate 			    // Store any text first.
10160Sstevel@tonic-gate 
10170Sstevel@tonic-gate 			    if (helpText.length() > 0) {
10180Sstevel@tonic-gate 				description = helpText;
10190Sstevel@tonic-gate 
10200Sstevel@tonic-gate 			    }
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 			    tk.pushBack();  // so same as above
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 			    break;
10250Sstevel@tonic-gate 			}
10260Sstevel@tonic-gate 		    } else if (tt == StreamTokenizer.TT_EOF) {
10270Sstevel@tonic-gate 			throw
10280Sstevel@tonic-gate 			    new ServiceLocationException(
10290Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
10300Sstevel@tonic-gate 				"template_end_error",
10310Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
10320Sstevel@tonic-gate 
10330Sstevel@tonic-gate 		    } else {
10340Sstevel@tonic-gate 
10350Sstevel@tonic-gate 			throw
10360Sstevel@tonic-gate 			    new ServiceLocationException(
10370Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
10380Sstevel@tonic-gate 				"template_unk_token",
10390Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate 		    }
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 		} while (true);
10440Sstevel@tonic-gate 
10450Sstevel@tonic-gate 		mask = DESCRIPTION_MASK;
10460Sstevel@tonic-gate 	    } else {
10470Sstevel@tonic-gate 
10480Sstevel@tonic-gate 		duplicate = true;
10490Sstevel@tonic-gate 	    }
10500Sstevel@tonic-gate 	} else if (id.equalsIgnoreCase(
10510Sstevel@tonic-gate 				SLPTemplateRegistry.SERVICE_URL_ATTR_ID)) {
10520Sstevel@tonic-gate 
10530Sstevel@tonic-gate 	    if ((found & URL_PATH_RULES_MASK) == 0) {
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate 		String serviceURLGrammer = "";
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 		// Pull everything out of the rdr StringReader until empty.
10580Sstevel@tonic-gate 
10590Sstevel@tonic-gate 		int ic;
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 		while ((ic = rdr.read()) != -1) {
10620Sstevel@tonic-gate 		    serviceURLGrammer += (char)ic;
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate 		}
10650Sstevel@tonic-gate 
10660Sstevel@tonic-gate 		serviceURLGrammer += "\n";
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate 		// Need to continue parsing service URL syntax until we
10690Sstevel@tonic-gate 		// reach a blank line.
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate 		tt = StreamTokenizer.TT_EOL;
10720Sstevel@tonic-gate 
10730Sstevel@tonic-gate 		do {
10740Sstevel@tonic-gate 		    int ptt = tt;
10750Sstevel@tonic-gate 		    tt = tk.nextToken();
10760Sstevel@tonic-gate 
10770Sstevel@tonic-gate 		    if (tt == StreamTokenizer.TT_WORD) {
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate 			serviceURLGrammer = serviceURLGrammer + tk.sval + "\n";
10800Sstevel@tonic-gate 
10810Sstevel@tonic-gate 		    } else if (tt == StreamTokenizer.TT_EOL) {
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate 			// If previous token was end of line, quit.
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate 			if (ptt == StreamTokenizer.TT_EOL) {
10860Sstevel@tonic-gate 
10870Sstevel@tonic-gate 			    // Store any text first.
10880Sstevel@tonic-gate 
10890Sstevel@tonic-gate 			    if (serviceURLGrammer.length() > 0) {
10900Sstevel@tonic-gate 				URLSyntax = serviceURLGrammer;
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate 			    }
10930Sstevel@tonic-gate 
10940Sstevel@tonic-gate 			    tk.pushBack();  // so same as above.
10950Sstevel@tonic-gate 
10960Sstevel@tonic-gate 			    break;
10970Sstevel@tonic-gate 			}
10980Sstevel@tonic-gate 		    } else if (tt == StreamTokenizer.TT_EOF) {
10990Sstevel@tonic-gate 			throw
11000Sstevel@tonic-gate 			    new ServiceLocationException(
11010Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
11020Sstevel@tonic-gate 				"template_end_error",
11030Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
11040Sstevel@tonic-gate 
11050Sstevel@tonic-gate 		    } else {
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate 			throw
11080Sstevel@tonic-gate 			    new ServiceLocationException(
11090Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
11100Sstevel@tonic-gate 				"template_unk_token",
11110Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
11120Sstevel@tonic-gate 
11130Sstevel@tonic-gate 		    }
11140Sstevel@tonic-gate 
11150Sstevel@tonic-gate 		} while (true);
11160Sstevel@tonic-gate 
11170Sstevel@tonic-gate 		mask = URL_PATH_RULES_MASK;
11180Sstevel@tonic-gate 	    } else {
11190Sstevel@tonic-gate 
11200Sstevel@tonic-gate 		duplicate = true;
11210Sstevel@tonic-gate 	    }
11220Sstevel@tonic-gate 	} else {
11230Sstevel@tonic-gate 
11240Sstevel@tonic-gate 	    throw
11250Sstevel@tonic-gate 		new ServiceLocationException(
11260Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
11270Sstevel@tonic-gate 				"template_nontattribute_err",
11280Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
11290Sstevel@tonic-gate 
11300Sstevel@tonic-gate 	}
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 	// Throw exception if a duplicate definition was detected.
11330Sstevel@tonic-gate 
11340Sstevel@tonic-gate 	if (duplicate) {
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate 	    throw
11370Sstevel@tonic-gate 		new ServiceLocationException(
11380Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
11390Sstevel@tonic-gate 				"template_dup_def",
11400Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
11410Sstevel@tonic-gate 
11420Sstevel@tonic-gate 	}
11430Sstevel@tonic-gate 
11440Sstevel@tonic-gate 
11450Sstevel@tonic-gate 	// Make sure the assignment ends with a blank line.
11460Sstevel@tonic-gate 
11470Sstevel@tonic-gate 	if ((tt = tk.nextToken()) != StreamTokenizer.TT_EOL) {
11480Sstevel@tonic-gate 
11490Sstevel@tonic-gate 	    throw
11500Sstevel@tonic-gate 		new ServiceLocationException(
11510Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
11520Sstevel@tonic-gate 				"template_attr_syntax",
11530Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
11540Sstevel@tonic-gate 
11550Sstevel@tonic-gate 	}
11560Sstevel@tonic-gate 
11570Sstevel@tonic-gate 	return mask;
11580Sstevel@tonic-gate 
11590Sstevel@tonic-gate     }
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate 
11620Sstevel@tonic-gate     // Parse the attributes from the tokenizer.
11630Sstevel@tonic-gate 
parseAttributes(StreamTokenizer tk)11640Sstevel@tonic-gate     private void parseAttributes(StreamTokenizer tk)
11650Sstevel@tonic-gate 	throws ServiceLocationException {
11660Sstevel@tonic-gate 
11670Sstevel@tonic-gate 	try {
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate 	    do {
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate 		// Check if at end of file yet.
11720Sstevel@tonic-gate 
11730Sstevel@tonic-gate 		int tt = tk.nextToken();
11740Sstevel@tonic-gate 
11750Sstevel@tonic-gate 		if (tt == StreamTokenizer.TT_EOF) {
11760Sstevel@tonic-gate 		    break;
11770Sstevel@tonic-gate 		}
11780Sstevel@tonic-gate 
11790Sstevel@tonic-gate 		// If not, push token back so we can get it next time.
11800Sstevel@tonic-gate 
11810Sstevel@tonic-gate 		tk.pushBack();
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate 		// Parse off the attribute descriptor.
11840Sstevel@tonic-gate 
11850Sstevel@tonic-gate 		AttributeDescriptor attDesc = parseAttribute(tk);
11860Sstevel@tonic-gate 
11870Sstevel@tonic-gate 		// Check whether default values, if any, are correct.
11880Sstevel@tonic-gate 
11890Sstevel@tonic-gate 		checkDefaultValues(attDesc);
11900Sstevel@tonic-gate 
11910Sstevel@tonic-gate 		// If the attribute already exists, then throw exception.
11920Sstevel@tonic-gate 		//  We could arguably replace existing, but it might
11930Sstevel@tonic-gate 		//  suprise the user.
11940Sstevel@tonic-gate 
11950Sstevel@tonic-gate 		String attrId = attDesc.getId().toLowerCase();
11960Sstevel@tonic-gate 
11970Sstevel@tonic-gate 		if (attributeDescriptors.get(attrId) != null) {
11980Sstevel@tonic-gate 
11990Sstevel@tonic-gate 		    throw
12000Sstevel@tonic-gate 			new ServiceLocationException(
12010Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
12020Sstevel@tonic-gate 				"template_dup_def",
12030Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
12040Sstevel@tonic-gate 
12050Sstevel@tonic-gate 		}
12060Sstevel@tonic-gate 
12070Sstevel@tonic-gate 		// Add the attribute to the descriptor table.
12080Sstevel@tonic-gate 
12090Sstevel@tonic-gate 		attributeDescriptors.put(attrId, attDesc);
12100Sstevel@tonic-gate 
12110Sstevel@tonic-gate 	    } while (true);
12120Sstevel@tonic-gate 
12130Sstevel@tonic-gate 	} catch (IOException ex) {
12140Sstevel@tonic-gate 
12150Sstevel@tonic-gate 	    throw
12160Sstevel@tonic-gate 		new ServiceLocationException(
12170Sstevel@tonic-gate 				ServiceLocationException.INTERNAL_SYSTEM_ERROR,
12180Sstevel@tonic-gate 				"template_io_error",
12190Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
12200Sstevel@tonic-gate 	}
12210Sstevel@tonic-gate 
12220Sstevel@tonic-gate     }
12230Sstevel@tonic-gate 
12240Sstevel@tonic-gate     // Parse a single attribute description from the tokenizer.
12250Sstevel@tonic-gate 
12260Sstevel@tonic-gate     private AttributeDescriptor
parseAttribute(StreamTokenizer tk)12270Sstevel@tonic-gate 	parseAttribute(StreamTokenizer tk) throws ServiceLocationException {
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate 	AttributeDescriptor attDesc = new AttributeDescriptor();
12300Sstevel@tonic-gate 	int lineno = 0;
12310Sstevel@tonic-gate 
12320Sstevel@tonic-gate 	try {
12330Sstevel@tonic-gate 
12340Sstevel@tonic-gate 	    // Parse the string for attribute id, type, and flags.
12350Sstevel@tonic-gate 
12360Sstevel@tonic-gate 	    lineno = tk.lineno();
12370Sstevel@tonic-gate 
12380Sstevel@tonic-gate 	    int tt = tk.nextToken();
12390Sstevel@tonic-gate 
12400Sstevel@tonic-gate 	    if (tt != StreamTokenizer.TT_WORD) {
12410Sstevel@tonic-gate 		throw
12420Sstevel@tonic-gate 		    new ServiceLocationException(
12430Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
12440Sstevel@tonic-gate 				"template_attr_syntax",
12450Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
12460Sstevel@tonic-gate 	    }
12470Sstevel@tonic-gate 
12480Sstevel@tonic-gate 	    StreamTokenizer stk =
12490Sstevel@tonic-gate 		new StreamTokenizer(new StringReader(tk.sval));
12500Sstevel@tonic-gate 
12510Sstevel@tonic-gate 	    initIdChar(stk);
12520Sstevel@tonic-gate 
12530Sstevel@tonic-gate 	    // Parse the attribute id.
12540Sstevel@tonic-gate 
12550Sstevel@tonic-gate 	    parseId(stk, attDesc, lineno);
12560Sstevel@tonic-gate 
12570Sstevel@tonic-gate 	    // Parse the type and flags.
12580Sstevel@tonic-gate 
12590Sstevel@tonic-gate 	    parseTypeAndFlags(stk, attDesc, lineno);
12600Sstevel@tonic-gate 
12610Sstevel@tonic-gate 	    tt = tk.nextToken();
12620Sstevel@tonic-gate 
12630Sstevel@tonic-gate 	    if (tt == StreamTokenizer.TT_EOF) {
12640Sstevel@tonic-gate 
12650Sstevel@tonic-gate 		throw
12660Sstevel@tonic-gate 		    new ServiceLocationException(
12670Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
12680Sstevel@tonic-gate 				"template_end_error",
12690Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
12700Sstevel@tonic-gate 
12710Sstevel@tonic-gate 	    }
12720Sstevel@tonic-gate 
12730Sstevel@tonic-gate 	    if (tt != StreamTokenizer.TT_EOL) {
12740Sstevel@tonic-gate 
12750Sstevel@tonic-gate 		throw
12760Sstevel@tonic-gate 		    new ServiceLocationException(
12770Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
12780Sstevel@tonic-gate 				"template_unk_token",
12790Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
12800Sstevel@tonic-gate 
12810Sstevel@tonic-gate 	    }
12820Sstevel@tonic-gate 
12830Sstevel@tonic-gate 	    // Parse initial values.
12840Sstevel@tonic-gate 
12850Sstevel@tonic-gate 	    if (!attDesc.getIsKeyword()) {
12860Sstevel@tonic-gate 
12870Sstevel@tonic-gate 		String tok = "";
12880Sstevel@tonic-gate 
12890Sstevel@tonic-gate 		// Read in entire list.
12900Sstevel@tonic-gate 
12910Sstevel@tonic-gate 		do {
12920Sstevel@tonic-gate 		    int ptt = tt;
12930Sstevel@tonic-gate 		    lineno = tk.lineno();
12940Sstevel@tonic-gate 		    tt = tk.nextToken();
12950Sstevel@tonic-gate 
12960Sstevel@tonic-gate 		    if (tt == StreamTokenizer.TT_WORD) {
12970Sstevel@tonic-gate 
12980Sstevel@tonic-gate 			// Trim line, check for '#', indicating end of list.
12990Sstevel@tonic-gate 
13000Sstevel@tonic-gate 			String line = tk.sval.trim();
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate 			if (line.charAt(0) == TT_FIELD) {
13030Sstevel@tonic-gate 			    // it's help text already.
13040Sstevel@tonic-gate 
13050Sstevel@tonic-gate 			    if (tok.length() > 0) {
13060Sstevel@tonic-gate 				stk =
13070Sstevel@tonic-gate 				    new StreamTokenizer(new StringReader(tok));
13080Sstevel@tonic-gate 				parseDefaultValues(stk, attDesc, lineno);
13090Sstevel@tonic-gate 			    }
13100Sstevel@tonic-gate 
13110Sstevel@tonic-gate 			    tk.pushBack();
13120Sstevel@tonic-gate 			    break;
13130Sstevel@tonic-gate 
13140Sstevel@tonic-gate 			} else {
13150Sstevel@tonic-gate 
13160Sstevel@tonic-gate 			    // Otherwise concatenate onto growing list.
13170Sstevel@tonic-gate 
13180Sstevel@tonic-gate 			    tok = tok + line;
13190Sstevel@tonic-gate 
13200Sstevel@tonic-gate 			}
13210Sstevel@tonic-gate 
13220Sstevel@tonic-gate 		    } else if (tt == StreamTokenizer.TT_EOL) {
13230Sstevel@tonic-gate 
13240Sstevel@tonic-gate 			if (ptt == StreamTokenizer.TT_EOL) {
13250Sstevel@tonic-gate 			    // end of attribute definition.
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate 			    // Process any accumulated list.
13280Sstevel@tonic-gate 
13290Sstevel@tonic-gate 			    if (tok.length() > 0) {
13300Sstevel@tonic-gate 				stk =
13310Sstevel@tonic-gate 				    new StreamTokenizer(new StringReader(tok));
13320Sstevel@tonic-gate 				parseDefaultValues(stk, attDesc, lineno);
13330Sstevel@tonic-gate 			    }
13340Sstevel@tonic-gate 
13350Sstevel@tonic-gate 			    return attDesc;
13360Sstevel@tonic-gate 
13370Sstevel@tonic-gate 			}
13380Sstevel@tonic-gate 		    } else if (tt == StreamTokenizer.TT_EOF) {
13390Sstevel@tonic-gate 			throw
13400Sstevel@tonic-gate 			    new ServiceLocationException(
13410Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
13420Sstevel@tonic-gate 				"template_end_error",
13430Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
13440Sstevel@tonic-gate 
13450Sstevel@tonic-gate 		    } else {
13460Sstevel@tonic-gate 
13470Sstevel@tonic-gate 			throw
13480Sstevel@tonic-gate 			    new ServiceLocationException(
13490Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
13500Sstevel@tonic-gate 				"template_unk_token",
13510Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
13520Sstevel@tonic-gate 
13530Sstevel@tonic-gate 		    }
13540Sstevel@tonic-gate 
13550Sstevel@tonic-gate 		} while (true);
13560Sstevel@tonic-gate 
13570Sstevel@tonic-gate 	    } else {
13580Sstevel@tonic-gate 		attDesc.setDefaultValues(null);
13590Sstevel@tonic-gate 		attDesc.setAllowedValues(null);
13600Sstevel@tonic-gate 
13610Sstevel@tonic-gate 		// Check for end of definition.
13620Sstevel@tonic-gate 
13630Sstevel@tonic-gate 		if ((tt = tk.nextToken()) == StreamTokenizer.TT_EOL) {
13640Sstevel@tonic-gate 		    return attDesc;
13650Sstevel@tonic-gate 
13660Sstevel@tonic-gate 		} else if (tt == StreamTokenizer.TT_WORD) {
13670Sstevel@tonic-gate 
13680Sstevel@tonic-gate 		    // Check for start of help text.
13690Sstevel@tonic-gate 
13700Sstevel@tonic-gate 		    String line = tk.sval.trim();
13710Sstevel@tonic-gate 
13720Sstevel@tonic-gate 		    if (line.charAt(0) != TT_FIELD) {
13730Sstevel@tonic-gate 			throw
13740Sstevel@tonic-gate 			    new ServiceLocationException(
13750Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
13760Sstevel@tonic-gate 				"template_attr_syntax",
13770Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate 		    } else {
13800Sstevel@tonic-gate 
13810Sstevel@tonic-gate 			tk.pushBack();
13820Sstevel@tonic-gate 
13830Sstevel@tonic-gate 		    }
13840Sstevel@tonic-gate 
13850Sstevel@tonic-gate 		} else if (tt == StreamTokenizer.TT_EOF) {
13860Sstevel@tonic-gate 		    throw
13870Sstevel@tonic-gate 			new ServiceLocationException(
13880Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
13890Sstevel@tonic-gate 				"template_end_error",
13900Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
13910Sstevel@tonic-gate 
13920Sstevel@tonic-gate 		} else {
13930Sstevel@tonic-gate 
13940Sstevel@tonic-gate 		    throw
13950Sstevel@tonic-gate 			new ServiceLocationException(
13960Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
13970Sstevel@tonic-gate 				"template_unk_token",
13980Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
13990Sstevel@tonic-gate 
14000Sstevel@tonic-gate 		}
14010Sstevel@tonic-gate 	    }
14020Sstevel@tonic-gate 
14030Sstevel@tonic-gate 
14040Sstevel@tonic-gate 	    // Parse help text.
14050Sstevel@tonic-gate 
14060Sstevel@tonic-gate 	    String helpText = "";
14070Sstevel@tonic-gate 
14080Sstevel@tonic-gate 	    do {
14090Sstevel@tonic-gate 		int ptt = tt;
14100Sstevel@tonic-gate 		lineno = tk.lineno();
14110Sstevel@tonic-gate 		tt = tk.nextToken();
14120Sstevel@tonic-gate 
14130Sstevel@tonic-gate 		if (tt == StreamTokenizer.TT_WORD) {
14140Sstevel@tonic-gate 
14150Sstevel@tonic-gate 		    // Check for end of help text.
14160Sstevel@tonic-gate 
14170Sstevel@tonic-gate 		    String line = tk.sval.trim();
14180Sstevel@tonic-gate 
14190Sstevel@tonic-gate 		    if (line.charAt(0) == TT_FIELD) {
14200Sstevel@tonic-gate 
14210Sstevel@tonic-gate 			// Help text is collected verbatim after '#'.
14220Sstevel@tonic-gate 
14230Sstevel@tonic-gate 			helpText =
14240Sstevel@tonic-gate 			    helpText + line.substring(1) + "\n";
14250Sstevel@tonic-gate 
14260Sstevel@tonic-gate 		    } else {
14270Sstevel@tonic-gate 
14280Sstevel@tonic-gate 			// We've reached the end of the help text. Store it
14290Sstevel@tonic-gate 			//  and break out of the loop.
14300Sstevel@tonic-gate 
14310Sstevel@tonic-gate 			if (helpText.length() > 0) {
14320Sstevel@tonic-gate 			    attDesc.setDescription(helpText);
14330Sstevel@tonic-gate 			}
14340Sstevel@tonic-gate 
14350Sstevel@tonic-gate 			tk.pushBack();
14360Sstevel@tonic-gate 			break;
14370Sstevel@tonic-gate 
14380Sstevel@tonic-gate 		    }
14390Sstevel@tonic-gate 
14400Sstevel@tonic-gate 		} else if (tt == StreamTokenizer.TT_EOL ||
14410Sstevel@tonic-gate 			   tt == StreamTokenizer.TT_EOF) {
14420Sstevel@tonic-gate 
14430Sstevel@tonic-gate 		    // If previous token was end of line, quit.
14440Sstevel@tonic-gate 
14450Sstevel@tonic-gate 		    if (ptt == StreamTokenizer.TT_EOL) {
14460Sstevel@tonic-gate 
14470Sstevel@tonic-gate 			// Store any text first.
14480Sstevel@tonic-gate 
14490Sstevel@tonic-gate 			if (helpText.length() > 0) {
14500Sstevel@tonic-gate 			    attDesc.setDescription(helpText);
14510Sstevel@tonic-gate 			}
14520Sstevel@tonic-gate 
14530Sstevel@tonic-gate 			// If this is a keyword attribute, set the allowed
14540Sstevel@tonic-gate 			//  values list to null.
14550Sstevel@tonic-gate 
14560Sstevel@tonic-gate 			if (attDesc.getIsKeyword()) {
14570Sstevel@tonic-gate 			    attDesc.setAllowedValues(null);
14580Sstevel@tonic-gate 			}
14590Sstevel@tonic-gate 
14600Sstevel@tonic-gate 			return attDesc;
14610Sstevel@tonic-gate 
14620Sstevel@tonic-gate 		    } else if (tt == StreamTokenizer.TT_EOF) {
14630Sstevel@tonic-gate 
14640Sstevel@tonic-gate 			// Error if previous token wasn't EOL.
14650Sstevel@tonic-gate 
14660Sstevel@tonic-gate 			throw
14670Sstevel@tonic-gate 			    new ServiceLocationException(
14680Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
14690Sstevel@tonic-gate 				"template_end_error",
14700Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
14710Sstevel@tonic-gate 		    }
14720Sstevel@tonic-gate 
14730Sstevel@tonic-gate 		} else {
14740Sstevel@tonic-gate 
14750Sstevel@tonic-gate 		    throw
14760Sstevel@tonic-gate 			new ServiceLocationException(
14770Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
14780Sstevel@tonic-gate 				"template_unk_token",
14790Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
14800Sstevel@tonic-gate 		}
14810Sstevel@tonic-gate 
14820Sstevel@tonic-gate 	    } while (true);
14830Sstevel@tonic-gate 
14840Sstevel@tonic-gate 	    // Parse allowed values.
14850Sstevel@tonic-gate 
14860Sstevel@tonic-gate 	    if (!attDesc.getIsKeyword()) {
14870Sstevel@tonic-gate 
14880Sstevel@tonic-gate 		String tok = "";
14890Sstevel@tonic-gate 
14900Sstevel@tonic-gate 		// Read in entire list.
14910Sstevel@tonic-gate 
14920Sstevel@tonic-gate 		do {
14930Sstevel@tonic-gate 		    int ptt = tt;
14940Sstevel@tonic-gate 		    lineno = tk.lineno();
14950Sstevel@tonic-gate 		    tt = tk.nextToken();
14960Sstevel@tonic-gate 
14970Sstevel@tonic-gate 		    if (tt == StreamTokenizer.TT_WORD) {
14980Sstevel@tonic-gate 
14990Sstevel@tonic-gate 			// Concatenate onto growing list.
15000Sstevel@tonic-gate 
15010Sstevel@tonic-gate 			tok = tok + tk.sval;
15020Sstevel@tonic-gate 
15030Sstevel@tonic-gate 		    } else if (tt == StreamTokenizer.TT_EOL) {
15040Sstevel@tonic-gate 
15050Sstevel@tonic-gate 			if (ptt == StreamTokenizer.TT_EOL) {
15060Sstevel@tonic-gate 			    // end of attribute definition.
15070Sstevel@tonic-gate 
15080Sstevel@tonic-gate 			    // Process any accumulated list.
15090Sstevel@tonic-gate 
15100Sstevel@tonic-gate 			    if (tok.length() > 0) {
15110Sstevel@tonic-gate 				stk =
15120Sstevel@tonic-gate 				    new StreamTokenizer(new StringReader(tok));
15130Sstevel@tonic-gate 				parseAllowedValues(stk, attDesc, lineno);
15140Sstevel@tonic-gate 			    }
15150Sstevel@tonic-gate 
15160Sstevel@tonic-gate 			    return attDesc;
15170Sstevel@tonic-gate 
15180Sstevel@tonic-gate 			}
15190Sstevel@tonic-gate 		    } else if (tt == StreamTokenizer.TT_EOF) {
15200Sstevel@tonic-gate 			throw
15210Sstevel@tonic-gate 			    new ServiceLocationException(
15220Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
15230Sstevel@tonic-gate 				"template_end_error",
15240Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
15250Sstevel@tonic-gate 
15260Sstevel@tonic-gate 		    } else {
15270Sstevel@tonic-gate 
15280Sstevel@tonic-gate 			throw
15290Sstevel@tonic-gate 			    new ServiceLocationException(
15300Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
15310Sstevel@tonic-gate 				"template_unk_token",
15320Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
15330Sstevel@tonic-gate 		    }
15340Sstevel@tonic-gate 
15350Sstevel@tonic-gate 		} while (true);
15360Sstevel@tonic-gate 
15370Sstevel@tonic-gate 	    } else {
15380Sstevel@tonic-gate 
15390Sstevel@tonic-gate 		// Error. Keyword attribute should have ended during help text
15400Sstevel@tonic-gate 		//  parsing or before.
15410Sstevel@tonic-gate 
15420Sstevel@tonic-gate 		throw
15430Sstevel@tonic-gate 		    new ServiceLocationException(
15440Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
15450Sstevel@tonic-gate 				"template_attr_syntax",
15460Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
15470Sstevel@tonic-gate 	    }
15480Sstevel@tonic-gate 
15490Sstevel@tonic-gate 	} catch (IOException ex) {
15500Sstevel@tonic-gate 
15510Sstevel@tonic-gate 	    throw
15520Sstevel@tonic-gate 		new ServiceLocationException(
15530Sstevel@tonic-gate 				ServiceLocationException.INTERNAL_SYSTEM_ERROR,
15540Sstevel@tonic-gate 				"template_io_error",
15550Sstevel@tonic-gate 				new Object[] {
15560Sstevel@tonic-gate 		    Integer.toString(tk.lineno()),
15570Sstevel@tonic-gate 			ex.getMessage()});
15580Sstevel@tonic-gate 	}
15590Sstevel@tonic-gate 
15600Sstevel@tonic-gate     }
15610Sstevel@tonic-gate 
15620Sstevel@tonic-gate     // Check whether the default values, if any, are correct.
15630Sstevel@tonic-gate 
checkDefaultValues(AttributeDescriptor attDesc)15640Sstevel@tonic-gate     private void checkDefaultValues(AttributeDescriptor attDesc)
15650Sstevel@tonic-gate 	throws ServiceLocationException {
15660Sstevel@tonic-gate 
15670Sstevel@tonic-gate 	// Don't bother if it's a keyword attribute, parsing has checked.
15680Sstevel@tonic-gate 
15690Sstevel@tonic-gate 	if (attDesc.getIsKeyword()) {
15700Sstevel@tonic-gate 	    return;
15710Sstevel@tonic-gate 	}
15720Sstevel@tonic-gate 
15730Sstevel@tonic-gate 	Enumeration init = attDesc.getDefaultValues();
15740Sstevel@tonic-gate 	Enumeration en = attDesc.getAllowedValues();
15750Sstevel@tonic-gate 	Vector allowed = new Vector();
15760Sstevel@tonic-gate 	String attDescType = attDesc.getValueType();
15770Sstevel@tonic-gate 
15780Sstevel@tonic-gate 	// First, collect the allowed values.
15790Sstevel@tonic-gate 
15800Sstevel@tonic-gate 	while (en.hasMoreElements()) {
15810Sstevel@tonic-gate 	    Object allval = en.nextElement();
15820Sstevel@tonic-gate 
15830Sstevel@tonic-gate 	    // Lower case strings and create opaques for comparison
15840Sstevel@tonic-gate 	    // if type is opaque.
15850Sstevel@tonic-gate 
15860Sstevel@tonic-gate 	    if (attDescType.equals(JAVA_STRING_TYPE)) {
15870Sstevel@tonic-gate 		allval = ((String)allval).toLowerCase();
15880Sstevel@tonic-gate 
15890Sstevel@tonic-gate 	    } else if (attDescType.equals(JAVA_OPAQUE_TYPE)) {
15900Sstevel@tonic-gate 		allval = new Opaque((byte[])allval);
15910Sstevel@tonic-gate 
15920Sstevel@tonic-gate 	    }
15930Sstevel@tonic-gate 
15940Sstevel@tonic-gate 	    allowed.addElement(allval);
15950Sstevel@tonic-gate 	}
15960Sstevel@tonic-gate 
15970Sstevel@tonic-gate 	// Now compare the allowed with the initial.
15980Sstevel@tonic-gate 
15990Sstevel@tonic-gate 	if (allowed.size() > 0) {
16000Sstevel@tonic-gate 
16010Sstevel@tonic-gate 	    // Error if allowed is restricted but no initializers.
16020Sstevel@tonic-gate 
16030Sstevel@tonic-gate 	    if (!init.hasMoreElements()) {
16040Sstevel@tonic-gate 
16050Sstevel@tonic-gate 		throw
16060Sstevel@tonic-gate 		    new ServiceLocationException(
16070Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
16080Sstevel@tonic-gate 				"template_no_init",
16090Sstevel@tonic-gate 				new Object[] {attDesc.getId()});
16100Sstevel@tonic-gate 
16110Sstevel@tonic-gate 	    }
16120Sstevel@tonic-gate 
16130Sstevel@tonic-gate 	    Object val = null;
16140Sstevel@tonic-gate 
16150Sstevel@tonic-gate 	    // Compare init values with allowed.
16160Sstevel@tonic-gate 
16170Sstevel@tonic-gate 	    while (init.hasMoreElements()) {
16180Sstevel@tonic-gate 		Object test = init.nextElement();
16190Sstevel@tonic-gate 		val = test; // for exception..
16200Sstevel@tonic-gate 
16210Sstevel@tonic-gate 		if (attDescType.equals(JAVA_STRING_TYPE)) {
16220Sstevel@tonic-gate 		    test = ((String)test).toLowerCase();
16230Sstevel@tonic-gate 
16240Sstevel@tonic-gate 		} else if (attDescType.equals(JAVA_OPAQUE_TYPE)) {
16250Sstevel@tonic-gate 		    test = new Opaque((byte[])test);
16260Sstevel@tonic-gate 
16270Sstevel@tonic-gate 		}
16280Sstevel@tonic-gate 
16290Sstevel@tonic-gate 		if (allowed.indexOf(test) != -1) {
16300Sstevel@tonic-gate 		    return; // found it!
16310Sstevel@tonic-gate 		}
16320Sstevel@tonic-gate 	    }
16330Sstevel@tonic-gate 	    // Initializer wasn't found.
16340Sstevel@tonic-gate 
16350Sstevel@tonic-gate 	    throw
16360Sstevel@tonic-gate 		new ServiceLocationException(
16370Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
16380Sstevel@tonic-gate 				"template_wrong_init",
16390Sstevel@tonic-gate 				new Object[] {
16400Sstevel@tonic-gate 		    val.toString(), attDesc.getId()});
16410Sstevel@tonic-gate 	}
16420Sstevel@tonic-gate     }
16430Sstevel@tonic-gate 
16440Sstevel@tonic-gate     // Parse the attribute's id string.
16450Sstevel@tonic-gate 
parseId(StreamTokenizer tk, AttributeDescriptor attDesc, int baseLineno)16460Sstevel@tonic-gate     private void parseId(StreamTokenizer tk,
16470Sstevel@tonic-gate 			 AttributeDescriptor attDesc,
16480Sstevel@tonic-gate 			 int baseLineno)
16490Sstevel@tonic-gate 	throws ServiceLocationException, IOException {
16500Sstevel@tonic-gate 
16510Sstevel@tonic-gate 	// Parse the attribute's identifier tag.
16520Sstevel@tonic-gate 
16530Sstevel@tonic-gate 	String id = parseWord(tk, baseLineno);
16540Sstevel@tonic-gate 
16550Sstevel@tonic-gate 	int tt = tk.nextToken();
16560Sstevel@tonic-gate 
16570Sstevel@tonic-gate 	// Parse the seperator.
16580Sstevel@tonic-gate 
16590Sstevel@tonic-gate 	if (tt != TT_EQUALS) {
16600Sstevel@tonic-gate 	    throw
16610Sstevel@tonic-gate 		new ServiceLocationException(
16620Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
16630Sstevel@tonic-gate 				"template_attr_syntax",
16640Sstevel@tonic-gate 				new Object[] {
16650Sstevel@tonic-gate 		    Integer.toString(tk.lineno() + baseLineno)});
16660Sstevel@tonic-gate 
16670Sstevel@tonic-gate 	}
16680Sstevel@tonic-gate 
16690Sstevel@tonic-gate 	// Expand out any escaped ``#''. It won't be handled by
16700Sstevel@tonic-gate 	// SLA.
16710Sstevel@tonic-gate 
16720Sstevel@tonic-gate 	id = unescapeHash(id);
16730Sstevel@tonic-gate 
16740Sstevel@tonic-gate 	// Expand out character escapes.
16750Sstevel@tonic-gate 
16760Sstevel@tonic-gate 	id =
16770Sstevel@tonic-gate 	    ServiceLocationAttribute.unescapeAttributeString(id, true);
16780Sstevel@tonic-gate 
16790Sstevel@tonic-gate 
16800Sstevel@tonic-gate 	attDesc.setId(id);
16810Sstevel@tonic-gate     }
16820Sstevel@tonic-gate 
16830Sstevel@tonic-gate     // Parse the attribute's type and flags.
16840Sstevel@tonic-gate 
16850Sstevel@tonic-gate     private void
parseTypeAndFlags(StreamTokenizer tk, AttributeDescriptor attDesc, int baseLineno)16860Sstevel@tonic-gate 	parseTypeAndFlags(StreamTokenizer tk,
16870Sstevel@tonic-gate 			  AttributeDescriptor attDesc,
16880Sstevel@tonic-gate 			  int baseLineno)
16890Sstevel@tonic-gate 	throws ServiceLocationException, IOException {
16900Sstevel@tonic-gate 
16910Sstevel@tonic-gate 	int existingFlags = 0;
16920Sstevel@tonic-gate 
16930Sstevel@tonic-gate 	// Parse the attribute's type.
16940Sstevel@tonic-gate 
16950Sstevel@tonic-gate 	String type = parseWord(tk, baseLineno);
16960Sstevel@tonic-gate 
16970Sstevel@tonic-gate 	checkAndAddType(type, attDesc, tk.lineno() + baseLineno);
16980Sstevel@tonic-gate 
16990Sstevel@tonic-gate 	// Parse the flags.
17000Sstevel@tonic-gate 
17010Sstevel@tonic-gate 	do {
17020Sstevel@tonic-gate 
17030Sstevel@tonic-gate 	    // Check if any flags are left.
17040Sstevel@tonic-gate 
17050Sstevel@tonic-gate 	    if (tk.nextToken() == StreamTokenizer.TT_EOF) {
17060Sstevel@tonic-gate 		break;
17070Sstevel@tonic-gate 
17080Sstevel@tonic-gate 	    } else {
17090Sstevel@tonic-gate 		tk.pushBack();
17100Sstevel@tonic-gate 	    }
17110Sstevel@tonic-gate 
17120Sstevel@tonic-gate 	    int lineno = tk.lineno();
17130Sstevel@tonic-gate 
17140Sstevel@tonic-gate 	    // Parse the flag.
17150Sstevel@tonic-gate 
17160Sstevel@tonic-gate 	    String flag = parseWord(tk, baseLineno);
17170Sstevel@tonic-gate 
17180Sstevel@tonic-gate 	    // Error if flags with keyword.
17190Sstevel@tonic-gate 
17200Sstevel@tonic-gate 	    if (attDesc.getIsKeyword()) {
17210Sstevel@tonic-gate 		throw
17220Sstevel@tonic-gate 		    new ServiceLocationException(
17230Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
17240Sstevel@tonic-gate 				"template_attr_syntax",
17250Sstevel@tonic-gate 				new Object[] {
17260Sstevel@tonic-gate 			Integer.toString(tk.lineno() + baseLineno)});
17270Sstevel@tonic-gate 	    }
17280Sstevel@tonic-gate 
17290Sstevel@tonic-gate 
17300Sstevel@tonic-gate 	    // Check and assign it to the attribute.
17310Sstevel@tonic-gate 
17320Sstevel@tonic-gate 	    existingFlags =
17330Sstevel@tonic-gate 		existingFlags | checkAndAddFlag(flag,
17340Sstevel@tonic-gate 						existingFlags,
17350Sstevel@tonic-gate 						attDesc,
17360Sstevel@tonic-gate 						baseLineno + lineno);
17370Sstevel@tonic-gate 
17380Sstevel@tonic-gate 	} while (true);
17390Sstevel@tonic-gate     }
17400Sstevel@tonic-gate 
17410Sstevel@tonic-gate     // Parse the attribute's initial value(s).
17420Sstevel@tonic-gate 
parseDefaultValues(StreamTokenizer tk, AttributeDescriptor attDesc, int baseLineno)17430Sstevel@tonic-gate     private void parseDefaultValues(StreamTokenizer tk,
17440Sstevel@tonic-gate 				    AttributeDescriptor attDesc,
17450Sstevel@tonic-gate 				    int baseLineno)
17460Sstevel@tonic-gate 	throws ServiceLocationException, IOException {
17470Sstevel@tonic-gate 
17480Sstevel@tonic-gate 	// First get the vector of initial values.
17490Sstevel@tonic-gate 
17500Sstevel@tonic-gate 	Vector vals = parseValueList(tk, attDesc, baseLineno);
17510Sstevel@tonic-gate 
17520Sstevel@tonic-gate 	// Check whether it works for this attribute. Type
17530Sstevel@tonic-gate 	//  checking will be done by value list parsing.
17540Sstevel@tonic-gate 
17550Sstevel@tonic-gate 	if (!attDesc.getIsMultivalued() && vals.size() > 1) {
17560Sstevel@tonic-gate 	    throw
17570Sstevel@tonic-gate 		new ServiceLocationException(
17580Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
17590Sstevel@tonic-gate 				"template_attr_syntax",
17600Sstevel@tonic-gate 				new Object[] {
17610Sstevel@tonic-gate 		    Integer.toString(tk.lineno() + baseLineno)});
17620Sstevel@tonic-gate 	}
17630Sstevel@tonic-gate 
17640Sstevel@tonic-gate 	attDesc.setDefaultValues(vals);
17650Sstevel@tonic-gate     }
17660Sstevel@tonic-gate 
17670Sstevel@tonic-gate     // Parse the attribute's allowed values.
17680Sstevel@tonic-gate 
17690Sstevel@tonic-gate     private void
parseAllowedValues(StreamTokenizer tk, AttributeDescriptor attDesc, int baseLineno)17700Sstevel@tonic-gate 	parseAllowedValues(StreamTokenizer tk,
17710Sstevel@tonic-gate 			   AttributeDescriptor attDesc,
17720Sstevel@tonic-gate 			   int baseLineno)
17730Sstevel@tonic-gate 	throws ServiceLocationException, IOException {
17740Sstevel@tonic-gate 
17750Sstevel@tonic-gate 	// First get the vector of all allowed values.
17760Sstevel@tonic-gate 
17770Sstevel@tonic-gate 	Vector vals = parseValueList(tk, attDesc, baseLineno);
17780Sstevel@tonic-gate 
17790Sstevel@tonic-gate 	// Now set the allowed value vector.
17800Sstevel@tonic-gate 
17810Sstevel@tonic-gate 	attDesc.setAllowedValues(vals);
17820Sstevel@tonic-gate     }
17830Sstevel@tonic-gate 
17840Sstevel@tonic-gate     // Parse a value list.
17850Sstevel@tonic-gate 
parseValueList(StreamTokenizer stk, AttributeDescriptor attDesc, int baseLineno)17860Sstevel@tonic-gate     private Vector parseValueList(StreamTokenizer stk,
17870Sstevel@tonic-gate 				  AttributeDescriptor attDesc,
17880Sstevel@tonic-gate 				  int baseLineno)
17890Sstevel@tonic-gate 	throws ServiceLocationException, IOException {
17900Sstevel@tonic-gate 
17910Sstevel@tonic-gate 	Vector req = new Vector();
17920Sstevel@tonic-gate 
17930Sstevel@tonic-gate 	// Set up the tokenizer according to the type of the
17940Sstevel@tonic-gate 	//  attribute.
17950Sstevel@tonic-gate 
17960Sstevel@tonic-gate 	String type = attDesc.getValueType();
17970Sstevel@tonic-gate 
17980Sstevel@tonic-gate 	if (type.equals(JAVA_STRING_TYPE) || type.equals(JAVA_OPAQUE_TYPE)) {
17990Sstevel@tonic-gate 	    initStringItemChar(stk);
18000Sstevel@tonic-gate 	} else if (type.equals(JAVA_INTEGER_TYPE)) {
18010Sstevel@tonic-gate 	    initIntItemChar(stk);
18020Sstevel@tonic-gate 	} else if (type.equals(JAVA_BOOLEAN_TYPE)) {
18030Sstevel@tonic-gate 	    initIdChar(stk);
18040Sstevel@tonic-gate 	}
18050Sstevel@tonic-gate 
18060Sstevel@tonic-gate 	// Parse through a potentially multivalued value list.
18070Sstevel@tonic-gate 
18080Sstevel@tonic-gate 	boolean wordRequired = true;	// true when a word is required,
18090Sstevel@tonic-gate 					// false when a comma required.
18100Sstevel@tonic-gate 	boolean syntaxError = false;
18110Sstevel@tonic-gate 	String reqTok = "";
18120Sstevel@tonic-gate 	int lineno = 0;
18130Sstevel@tonic-gate 
18140Sstevel@tonic-gate 	do {
18150Sstevel@tonic-gate 	    int tt = stk.nextToken();
18160Sstevel@tonic-gate 	    lineno = stk.lineno() + baseLineno;
18170Sstevel@tonic-gate 
18180Sstevel@tonic-gate 	    if (tt ==  StreamTokenizer.TT_WORD) {
18190Sstevel@tonic-gate 
18200Sstevel@tonic-gate 		// If a word isn't required, then the case is
18210Sstevel@tonic-gate 		//  "token token" and is an error.
18220Sstevel@tonic-gate 
18230Sstevel@tonic-gate 		if (!wordRequired) {
18240Sstevel@tonic-gate 		    syntaxError = true;
18250Sstevel@tonic-gate 		}
18260Sstevel@tonic-gate 
18270Sstevel@tonic-gate 		reqTok = stk.sval.trim();
18280Sstevel@tonic-gate 
18290Sstevel@tonic-gate 		// Convert the value to the proper object.
18300Sstevel@tonic-gate 
18310Sstevel@tonic-gate 		Object reqVal = convertValue(type, reqTok, baseLineno);
18320Sstevel@tonic-gate 		req.addElement(reqVal);
18330Sstevel@tonic-gate 
18340Sstevel@tonic-gate 		wordRequired = false;
18350Sstevel@tonic-gate 
18360Sstevel@tonic-gate 	    } else if (tt == StreamTokenizer.TT_EOF) {
18370Sstevel@tonic-gate 
18380Sstevel@tonic-gate 		// If a word is required, then list ends with
18390Sstevel@tonic-gate 		//  a comma, so error.
18400Sstevel@tonic-gate 
18410Sstevel@tonic-gate 		if (wordRequired) {
18420Sstevel@tonic-gate 		    syntaxError = true;
18430Sstevel@tonic-gate 		}
18440Sstevel@tonic-gate 
18450Sstevel@tonic-gate 		break;
18460Sstevel@tonic-gate 
18470Sstevel@tonic-gate 	    } else if (tt == TT_COMMA) {
18480Sstevel@tonic-gate 
18490Sstevel@tonic-gate 		// If a word is required, then error. The case is ",,".
18500Sstevel@tonic-gate 
18510Sstevel@tonic-gate 		if (wordRequired) {
18520Sstevel@tonic-gate 		    syntaxError = true;
18530Sstevel@tonic-gate 		    break;
18540Sstevel@tonic-gate 		}
18550Sstevel@tonic-gate 
18560Sstevel@tonic-gate 		// Otherwise, the next token must be a word.
18570Sstevel@tonic-gate 
18580Sstevel@tonic-gate 		wordRequired = true;
18590Sstevel@tonic-gate 
18600Sstevel@tonic-gate 	    } else {
18610Sstevel@tonic-gate 
18620Sstevel@tonic-gate 		// No other tokens are allowed.
18630Sstevel@tonic-gate 
18640Sstevel@tonic-gate 		syntaxError = true;
18650Sstevel@tonic-gate 		break;
18660Sstevel@tonic-gate 	    }
18670Sstevel@tonic-gate 
18680Sstevel@tonic-gate 	} while (true);
18690Sstevel@tonic-gate 
18700Sstevel@tonic-gate 	if (syntaxError) {
18710Sstevel@tonic-gate 
18720Sstevel@tonic-gate 	    throw
18730Sstevel@tonic-gate 		new ServiceLocationException(
18740Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
18750Sstevel@tonic-gate 				"template_attr_syntax",
18760Sstevel@tonic-gate 				new Object[] {Integer.toString(lineno)});
18770Sstevel@tonic-gate 	}
18780Sstevel@tonic-gate 
18790Sstevel@tonic-gate 	return req;
18800Sstevel@tonic-gate 
18810Sstevel@tonic-gate     }
18820Sstevel@tonic-gate 
18830Sstevel@tonic-gate     // Check the type and add it to the attribute descriptor.
18840Sstevel@tonic-gate 
checkAndAddType(String type, AttributeDescriptor attDesc, int lineno)18850Sstevel@tonic-gate     private void checkAndAddType(String type,
18860Sstevel@tonic-gate 				 AttributeDescriptor attDesc,
18870Sstevel@tonic-gate 				 int lineno)
18880Sstevel@tonic-gate 	throws ServiceLocationException {
18890Sstevel@tonic-gate 
18900Sstevel@tonic-gate 	// Check token against recognized types.
18910Sstevel@tonic-gate 
18920Sstevel@tonic-gate 	if (type.equalsIgnoreCase(STRING_TYPE)) {
18930Sstevel@tonic-gate 	    attDesc.setValueType(JAVA_STRING_TYPE);
18940Sstevel@tonic-gate 
18950Sstevel@tonic-gate 	} else if (type.equalsIgnoreCase(INTEGER_TYPE)) {
18960Sstevel@tonic-gate 	    attDesc.setValueType(JAVA_INTEGER_TYPE);
18970Sstevel@tonic-gate 
18980Sstevel@tonic-gate 	} else if (type.equalsIgnoreCase(BOOLEAN_TYPE)) {
18990Sstevel@tonic-gate 	    attDesc.setValueType(JAVA_BOOLEAN_TYPE);
19000Sstevel@tonic-gate 
19010Sstevel@tonic-gate 	} else if (type.equalsIgnoreCase(OPAQUE_TYPE)) {
19020Sstevel@tonic-gate 	    attDesc.setValueType(JAVA_OPAQUE_TYPE);
19030Sstevel@tonic-gate 
19040Sstevel@tonic-gate 	} else if (type.equalsIgnoreCase(KEYWORD_TYPE)) {
19050Sstevel@tonic-gate 	    attDesc.setIsKeyword(true);
19060Sstevel@tonic-gate 
19070Sstevel@tonic-gate 	} else {
19080Sstevel@tonic-gate 
19090Sstevel@tonic-gate 	    throw
19100Sstevel@tonic-gate 		new ServiceLocationException(
19110Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
19120Sstevel@tonic-gate 				"template_not_slp_type",
19130Sstevel@tonic-gate 				new Object[] {Integer.toString(lineno)});
19140Sstevel@tonic-gate 	}
19150Sstevel@tonic-gate 
19160Sstevel@tonic-gate     }
19170Sstevel@tonic-gate 
19180Sstevel@tonic-gate     // Check the flag and add it to the attribute descriptor.
19190Sstevel@tonic-gate 
checkAndAddFlag(String flag, int matched, AttributeDescriptor attDesc, int lineno)19200Sstevel@tonic-gate     private int checkAndAddFlag(String flag,
19210Sstevel@tonic-gate 				int matched,
19220Sstevel@tonic-gate 				AttributeDescriptor attDesc,
19230Sstevel@tonic-gate 				int lineno)
19240Sstevel@tonic-gate 	throws ServiceLocationException {
19250Sstevel@tonic-gate 
19260Sstevel@tonic-gate 	boolean duplicate = false;
19270Sstevel@tonic-gate 
19280Sstevel@tonic-gate 	// We depend on the attribute descriptor being initialized to
19290Sstevel@tonic-gate 	// nothing, i.e. false for all flags and for keyword.
19300Sstevel@tonic-gate 
19310Sstevel@tonic-gate 	if (flag.equalsIgnoreCase(MULTIPLE_FLAG)) {
19320Sstevel@tonic-gate 
19330Sstevel@tonic-gate 	    if ((matched & MULTIPLE_MASK) != 0) {
19340Sstevel@tonic-gate 		duplicate = true;
19350Sstevel@tonic-gate 
19360Sstevel@tonic-gate 	    } else {
19370Sstevel@tonic-gate 
19380Sstevel@tonic-gate 		// Check for boolean. Booleans may not have
19390Sstevel@tonic-gate 		// multiple values.
19400Sstevel@tonic-gate 
19410Sstevel@tonic-gate 		if (attDesc.getValueType().equals(JAVA_BOOLEAN_TYPE)) {
19420Sstevel@tonic-gate 
19430Sstevel@tonic-gate 		    throw
19440Sstevel@tonic-gate 			new ServiceLocationException(
19450Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
19460Sstevel@tonic-gate 				"template_boolean_multi",
19470Sstevel@tonic-gate 				new Object[] {Integer.toString(lineno)});
19480Sstevel@tonic-gate 		}
19490Sstevel@tonic-gate 
19500Sstevel@tonic-gate 		attDesc.setIsMultivalued(true);
19510Sstevel@tonic-gate 		return MULTIPLE_MASK;
19520Sstevel@tonic-gate 
19530Sstevel@tonic-gate 	    }
19540Sstevel@tonic-gate 
19550Sstevel@tonic-gate 	} else if (flag.equalsIgnoreCase(LITERAL_FLAG)) {
19560Sstevel@tonic-gate 
19570Sstevel@tonic-gate 	    if ((matched & LITERAL_MASK) != 0) {
19580Sstevel@tonic-gate 		duplicate = true;
19590Sstevel@tonic-gate 
19600Sstevel@tonic-gate 	    } else {
19610Sstevel@tonic-gate 		attDesc.setIsLiteral(true);
19620Sstevel@tonic-gate 		return LITERAL_MASK;
19630Sstevel@tonic-gate 	    }
19640Sstevel@tonic-gate 
19650Sstevel@tonic-gate 	} else if (flag.equalsIgnoreCase(EXPLICIT_FLAG)) {
19660Sstevel@tonic-gate 
19670Sstevel@tonic-gate 	    if ((matched & EXPLICIT_MASK) != 0) {
19680Sstevel@tonic-gate 		duplicate = true;
19690Sstevel@tonic-gate 
19700Sstevel@tonic-gate 	    } else {
19710Sstevel@tonic-gate 		attDesc.setRequiresExplicitMatch(true);
19720Sstevel@tonic-gate 		return EXPLICIT_MASK;
19730Sstevel@tonic-gate 	    }
19740Sstevel@tonic-gate 
19750Sstevel@tonic-gate 	} else if (flag.equalsIgnoreCase(OPTIONAL_FLAG)) {
19760Sstevel@tonic-gate 
19770Sstevel@tonic-gate 	    if ((matched & OPTIONAL_MASK) != 0) {
19780Sstevel@tonic-gate 		duplicate = true;
19790Sstevel@tonic-gate 
19800Sstevel@tonic-gate 	    } else {
19810Sstevel@tonic-gate 		attDesc.setIsOptional(true);
19820Sstevel@tonic-gate 		return OPTIONAL_MASK;
19830Sstevel@tonic-gate 	    }
19840Sstevel@tonic-gate 
19850Sstevel@tonic-gate 	} else {
19860Sstevel@tonic-gate 
19870Sstevel@tonic-gate 	    throw
19880Sstevel@tonic-gate 		new ServiceLocationException(
19890Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
19900Sstevel@tonic-gate 				"template_invalid_attr_flag",
19910Sstevel@tonic-gate 				new Object[] {Integer.toString(lineno)});
19920Sstevel@tonic-gate 	}
19930Sstevel@tonic-gate 
19940Sstevel@tonic-gate 
19950Sstevel@tonic-gate 	if (duplicate) {
19960Sstevel@tonic-gate 	    throw
19970Sstevel@tonic-gate 		new ServiceLocationException(
19980Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
19990Sstevel@tonic-gate 				"template_dup_attr_flag",
20000Sstevel@tonic-gate 				new Object[] {Integer.toString(lineno)});
20010Sstevel@tonic-gate 	}
20020Sstevel@tonic-gate 
20030Sstevel@tonic-gate 	return 0; // never happens.
20040Sstevel@tonic-gate     }
20050Sstevel@tonic-gate 
20060Sstevel@tonic-gate     // Parse a word out of the tokenizer. The exact characters
20070Sstevel@tonic-gate     //  will depend on what the syntax tables have been set to.
20080Sstevel@tonic-gate 
parseWord(StreamTokenizer tk, int baseLineno)20090Sstevel@tonic-gate     private String parseWord(StreamTokenizer tk, int baseLineno)
20100Sstevel@tonic-gate 	throws ServiceLocationException, IOException {
20110Sstevel@tonic-gate 
20120Sstevel@tonic-gate 	int tt = tk.nextToken();
20130Sstevel@tonic-gate 
20140Sstevel@tonic-gate 	if (tt == StreamTokenizer.TT_WORD) {
20150Sstevel@tonic-gate 	    return (tk.sval);
20160Sstevel@tonic-gate 
20170Sstevel@tonic-gate 	} else {
20180Sstevel@tonic-gate 
20190Sstevel@tonic-gate 	    String errorToken = "";
20200Sstevel@tonic-gate 
20210Sstevel@tonic-gate 	    // Report the erroneous characters.
20220Sstevel@tonic-gate 
20230Sstevel@tonic-gate 	    if (tt == StreamTokenizer.TT_NUMBER) {
20240Sstevel@tonic-gate 		errorToken = Double.toString(tk.nval);
20250Sstevel@tonic-gate 	    } else if (tt == StreamTokenizer.TT_EOL) {
20260Sstevel@tonic-gate 		errorToken = "<end of line>";
20270Sstevel@tonic-gate 	    } else if (tt == StreamTokenizer.TT_EOF) {
20280Sstevel@tonic-gate 		errorToken = "<end of file>";
20290Sstevel@tonic-gate 	    } else {
20300Sstevel@tonic-gate 		errorToken = (new Character((char)tt)).toString();
20310Sstevel@tonic-gate 	    }
20320Sstevel@tonic-gate 
20330Sstevel@tonic-gate 	    throw
20340Sstevel@tonic-gate 		new ServiceLocationException(
20350Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
20360Sstevel@tonic-gate 				"template_invalid_tok",
20370Sstevel@tonic-gate 				new Object[] {
20380Sstevel@tonic-gate 		    Integer.toString(tk.lineno() + baseLineno)});
20390Sstevel@tonic-gate 
20400Sstevel@tonic-gate 	}
20410Sstevel@tonic-gate 
20420Sstevel@tonic-gate     }
20430Sstevel@tonic-gate 
20440Sstevel@tonic-gate     // Convert a value list token to the value.
20450Sstevel@tonic-gate 
convertValue(String type, String reqTok, int lineno)20460Sstevel@tonic-gate     private Object convertValue(String type,
20470Sstevel@tonic-gate 				String reqTok,
20480Sstevel@tonic-gate 				int lineno)
20490Sstevel@tonic-gate 	throws ServiceLocationException,
20500Sstevel@tonic-gate 	       IOException {
20510Sstevel@tonic-gate 
20520Sstevel@tonic-gate 	Object reqVal = null;
20530Sstevel@tonic-gate 
20540Sstevel@tonic-gate 	if (type.equals(JAVA_STRING_TYPE)) {
20550Sstevel@tonic-gate 
20560Sstevel@tonic-gate 	    // Expand out any escaped ``#''. It won't be handled by
20570Sstevel@tonic-gate 	    //  SLA.
20580Sstevel@tonic-gate 
20590Sstevel@tonic-gate 	    reqTok = unescapeHash(reqTok);
20600Sstevel@tonic-gate 
20610Sstevel@tonic-gate 	    // Expand out character escapes.
20620Sstevel@tonic-gate 
20630Sstevel@tonic-gate 	    reqVal =
20640Sstevel@tonic-gate 		ServiceLocationAttribute.unescapeAttributeString(reqTok,
20650Sstevel@tonic-gate 								 false);
20660Sstevel@tonic-gate 
20670Sstevel@tonic-gate 	} else if (type.equals(JAVA_INTEGER_TYPE)) {
20680Sstevel@tonic-gate 
20690Sstevel@tonic-gate 	    try {
20700Sstevel@tonic-gate 
20710Sstevel@tonic-gate 		reqVal = Integer.valueOf(reqTok);
20720Sstevel@tonic-gate 
20730Sstevel@tonic-gate 	    } catch (NumberFormatException ex) {
20740Sstevel@tonic-gate 
20750Sstevel@tonic-gate 		throw
20760Sstevel@tonic-gate 		    new ServiceLocationException(
20770Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
20780Sstevel@tonic-gate 				"template_expect_int",
20790Sstevel@tonic-gate 				new Object[] {
20800Sstevel@tonic-gate 			Integer.toString(lineno), reqTok });
20810Sstevel@tonic-gate 	    }
20820Sstevel@tonic-gate 	} else if (type.equals(JAVA_BOOLEAN_TYPE)) {
20830Sstevel@tonic-gate 
20840Sstevel@tonic-gate 	    // Boolean.valueOf() doesn't handle this properly.
20850Sstevel@tonic-gate 
20860Sstevel@tonic-gate 	    if (reqTok.equalsIgnoreCase(TRUE_TOKEN)) {
20870Sstevel@tonic-gate 
20880Sstevel@tonic-gate 		reqVal = new Boolean(true);
20890Sstevel@tonic-gate 
20900Sstevel@tonic-gate 	    } else if (reqTok.equalsIgnoreCase(FALSE_TOKEN)) {
20910Sstevel@tonic-gate 
20920Sstevel@tonic-gate 		reqVal = new Boolean(false);
20930Sstevel@tonic-gate 
20940Sstevel@tonic-gate 	    } else {
20950Sstevel@tonic-gate 
20960Sstevel@tonic-gate 		throw
20970Sstevel@tonic-gate 		    new ServiceLocationException(
20980Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
20990Sstevel@tonic-gate 				"template_expect_bool",
21000Sstevel@tonic-gate 				new Object[] {
21010Sstevel@tonic-gate 			Integer.toString(lineno), reqTok});
21020Sstevel@tonic-gate 	    }
21030Sstevel@tonic-gate 	} else if (type.equals(JAVA_OPAQUE_TYPE)) {
21040Sstevel@tonic-gate 
21050Sstevel@tonic-gate 	    reqVal = Opaque.unescapeByteArray(reqTok);
21060Sstevel@tonic-gate 
21070Sstevel@tonic-gate 	} else {
21080Sstevel@tonic-gate 
21090Sstevel@tonic-gate 	    Assert.slpassert(false,
21100Sstevel@tonic-gate 			  "template_attr_desc",
21110Sstevel@tonic-gate 			  new Object[0]);
21120Sstevel@tonic-gate 	}
21130Sstevel@tonic-gate 
21140Sstevel@tonic-gate 	return reqVal;
21150Sstevel@tonic-gate     }
21160Sstevel@tonic-gate 
21170Sstevel@tonic-gate     // Expand out any escaped hashes. Not handled by SLA.
21180Sstevel@tonic-gate 
unescapeHash(String str)21190Sstevel@tonic-gate     private String unescapeHash(String str) {
21200Sstevel@tonic-gate 
21210Sstevel@tonic-gate 	StringBuffer buf = new StringBuffer();
21220Sstevel@tonic-gate 	int len = ESC_HASH.length();
21230Sstevel@tonic-gate 	int i, j = 0;
21240Sstevel@tonic-gate 
21250Sstevel@tonic-gate 	for (i = str.indexOf(ESC_HASH, j);
21260Sstevel@tonic-gate 	    i != -1;
21270Sstevel@tonic-gate 	    i = str.indexOf(ESC_HASH, j)) {
21280Sstevel@tonic-gate 
21290Sstevel@tonic-gate 	    buf.append(str.substring(j, i));
21300Sstevel@tonic-gate 	    buf.append(HASH);
21310Sstevel@tonic-gate 	    j = i + len;
21320Sstevel@tonic-gate 	}
21330Sstevel@tonic-gate 
21340Sstevel@tonic-gate 	len = str.length();
21350Sstevel@tonic-gate 
21360Sstevel@tonic-gate 	if (j < len) {
21370Sstevel@tonic-gate 	    buf.append(str.substring(j, len));
21380Sstevel@tonic-gate 
21390Sstevel@tonic-gate 	}
21400Sstevel@tonic-gate 
21410Sstevel@tonic-gate 	return buf.toString();
21420Sstevel@tonic-gate     }
21430Sstevel@tonic-gate 
21440Sstevel@tonic-gate }
2145