17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
59a70fc3bSMark J. Nelson  * Common Development and Distribution License (the "License").
69a70fc3bSMark J. Nelson  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
227c478bd9Sstevel@tonic-gate  * Copyright (c) 1999-2001 by Sun Microsystems, Inc.
237c478bd9Sstevel@tonic-gate  * All rights reserved.
247c478bd9Sstevel@tonic-gate  *
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
27*55fea89dSDan Cross //  AttributeVerifier.java: An attribute verifier for SLP attributes.
287c478bd9Sstevel@tonic-gate //  Author:           James Kempf
297c478bd9Sstevel@tonic-gate //  Created On:       Thu Jun 19 10:51:32 1997
307c478bd9Sstevel@tonic-gate //  Last Modified By: James Kempf
317c478bd9Sstevel@tonic-gate //  Last Modified On: Mon Nov  9 10:21:02 1998
327c478bd9Sstevel@tonic-gate //  Update Count:     200
337c478bd9Sstevel@tonic-gate //
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate package com.sun.slp;
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate import java.util.*;
387c478bd9Sstevel@tonic-gate import java.io.*;
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate /**
417c478bd9Sstevel@tonic-gate  * The AttributeVerifier class implements the ServiceLocationAttributeVerifier
427c478bd9Sstevel@tonic-gate  * interface, but without committment to a particular mechanism for
437c478bd9Sstevel@tonic-gate  * obtaining the template defintion. Subclasses provide the mechanism,
447c478bd9Sstevel@tonic-gate  * and pass in the template to the parent as a Reader during object
45*55fea89dSDan Cross  * creation. The AttributeVerifier class parses tokens from the Reader and
467c478bd9Sstevel@tonic-gate  * constructs the attribute descriptor objects describing the attribute. These
477c478bd9Sstevel@tonic-gate  * are used during verification of the attribute. The AttributeVerifier
487c478bd9Sstevel@tonic-gate  * and implementations of the attribute descriptors are free to optimize
49*55fea89dSDan Cross  * space utilization by lazily evaluating portions of the attribute
507c478bd9Sstevel@tonic-gate  * template.
517c478bd9Sstevel@tonic-gate  *
527c478bd9Sstevel@tonic-gate  * @author James Kempf
537c478bd9Sstevel@tonic-gate  *
547c478bd9Sstevel@tonic-gate  */
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate class AttributeVerifier
577c478bd9Sstevel@tonic-gate     extends Object
587c478bd9Sstevel@tonic-gate     implements ServiceLocationAttributeVerifier {
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate     // Template specific escape.
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate     private static final String ESC_HASH = "\\23";
637c478bd9Sstevel@tonic-gate     private static final String HASH = "#";
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate     // Number of template attributes.
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate     private static final int TEMPLATE_ATTR_NO = 5;
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate     // Bitfields for found template attributes.
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate     private static final int SERVICE_MASK = 0x01;
727c478bd9Sstevel@tonic-gate     private static final int VERSION_MASK = 0x02;
737c478bd9Sstevel@tonic-gate     private static final int DESCRIPTION_MASK = 0x08;
747c478bd9Sstevel@tonic-gate     private static final int URL_PATH_RULES_MASK = 0x10;
757c478bd9Sstevel@tonic-gate 
76*55fea89dSDan Cross     // When all template attribute assignments are found.
777c478bd9Sstevel@tonic-gate 
78*55fea89dSDan Cross     private static final int TEMPLATE_FOUND = (SERVICE_MASK |
79*55fea89dSDan Cross 					       VERSION_MASK |
80*55fea89dSDan Cross 					       DESCRIPTION_MASK |
817c478bd9Sstevel@tonic-gate 					       URL_PATH_RULES_MASK);
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate     // These are the valid SLP types.
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate     private static final String INTEGER_TYPE = "integer";
867c478bd9Sstevel@tonic-gate     private static final String STRING_TYPE = "string";
877c478bd9Sstevel@tonic-gate     private static final String BOOLEAN_TYPE = "boolean";
887c478bd9Sstevel@tonic-gate     private static final String OPAQUE_TYPE = "opaque";
897c478bd9Sstevel@tonic-gate     private static final String KEYWORD_TYPE = "keyword";
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate     // These are the corresponding Java types. Package public so
927c478bd9Sstevel@tonic-gate     //  others (SLPConfig for example) can get at them.
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate     static final String JAVA_STRING_TYPE =
957c478bd9Sstevel@tonic-gate 	"java.lang.String";
96*55fea89dSDan Cross     static final String JAVA_INTEGER_TYPE =
977c478bd9Sstevel@tonic-gate 	"java.lang.Integer";
987c478bd9Sstevel@tonic-gate     static final String JAVA_BOOLEAN_TYPE =
997c478bd9Sstevel@tonic-gate 	"java.lang.Boolean";
1007c478bd9Sstevel@tonic-gate     static final String JAVA_OPAQUE_TYPE =
1017c478bd9Sstevel@tonic-gate 	"[B";
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate     // Tokens for boolean values.
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate     private static final String TRUE_TOKEN = "true";
1067c478bd9Sstevel@tonic-gate     private static final String FALSE_TOKEN = "false";
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate     // This is the number of flags.
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate     private static final int FLAG_NO = 4;
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate     // These are the flags.
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate     private static final String MULTIPLE_FLAG = "m";
1157c478bd9Sstevel@tonic-gate     private static final String LITERAL_FLAG = "l";
1167c478bd9Sstevel@tonic-gate     private static final String EXPLICIT_FLAG = "x";
1177c478bd9Sstevel@tonic-gate     private static final String OPTIONAL_FLAG = "o";
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate     // These masks help determine whether the flags have been duplicated.
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate     private static final byte MULTIPLE_MASK = 0x01;
1227c478bd9Sstevel@tonic-gate     private static final byte LITERAL_MASK = 0x02;
1237c478bd9Sstevel@tonic-gate     private static final byte EXPLICIT_MASK = 0x04;
1247c478bd9Sstevel@tonic-gate     private static final byte OPTIONAL_MASK = 0x08;
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate     // These are tokens for separator characters.
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate     private static final char TT_COMMA = ',';
1297c478bd9Sstevel@tonic-gate     private static final char TT_EQUALS = '=';
1307c478bd9Sstevel@tonic-gate     private static final char TT_FIELD = '#';
1317c478bd9Sstevel@tonic-gate     private static final char TT_ESCAPE = '\\';
1327c478bd9Sstevel@tonic-gate 
133*55fea89dSDan Cross     // This token is for checking version number
1347c478bd9Sstevel@tonic-gate     // attribute assignment.
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate     private static final char TT_PERIOD = '.';
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate     // Radix64 code characters.
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate     private static final char UPPER_START_CODE = 'A';
1417c478bd9Sstevel@tonic-gate     private static final char UPPER_END_CODE = 'Z';
1427c478bd9Sstevel@tonic-gate     private static final char LOWER_START_CODE = 'a';
1437c478bd9Sstevel@tonic-gate     private static final char LOWER_END_CODE = 'z';
1447c478bd9Sstevel@tonic-gate     private static final char NUMBER_START_CODE = '0';
1457c478bd9Sstevel@tonic-gate     private static final char NUMBER_END_CODE = '9';
1467c478bd9Sstevel@tonic-gate     private static final char EXTRA_CODE1 = '+';
1477c478bd9Sstevel@tonic-gate     private static final char EXTRA_CODE2 = '/';
1487c478bd9Sstevel@tonic-gate     private static final char PAD_CODE = '=';
1497c478bd9Sstevel@tonic-gate     private static final char LENGTH_SEPERATOR = ':';
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate     // The SLP service type of this template.
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate     private ServiceType serviceType;
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate     // The template's language locale.
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate     private Locale locale;
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate     // The template's version.
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate     private String version;
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate     // The template's URL syntax.
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate     private String URLSyntax;
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate     // The template's description.
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate     private String description;
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate     // The attribute descriptors.
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate     private Hashtable attributeDescriptors = new Hashtable();
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate     //
1767c478bd9Sstevel@tonic-gate     // Constructors.
1777c478bd9Sstevel@tonic-gate 
AttributeVerifier()1787c478bd9Sstevel@tonic-gate     AttributeVerifier() {
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate     }
1817c478bd9Sstevel@tonic-gate 
182*55fea89dSDan Cross     // Initialize the attribute verifier with a reader. Subclasses or clients
1837c478bd9Sstevel@tonic-gate     // pass in a Reader on the template that is used for parsing. This
1847c478bd9Sstevel@tonic-gate     // method is used when the template includes the template attributes
1857c478bd9Sstevel@tonic-gate     // and URL rules.
1867c478bd9Sstevel@tonic-gate 
initialize(Reader r)1877c478bd9Sstevel@tonic-gate     void initialize(Reader r) throws ServiceLocationException {
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	// Use a StreamTokenizer to parse.
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	StreamTokenizer tk = new StreamTokenizer(r);
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	// Initialize tokenizer for parsing main.
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 	initFieldChar(tk);
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 	// Now parse the attribute template, including template attributes.
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	parseTemplate(tk);
2007c478bd9Sstevel@tonic-gate     }
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate     // Initialize with this method when no template attributes are involved.
2037c478bd9Sstevel@tonic-gate 
initializeAttributesOnly(Reader r)204*55fea89dSDan Cross     void initializeAttributesOnly(Reader r)
2057c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	// Use a StreamTokenizer to parse.
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	StreamTokenizer tk = new StreamTokenizer(r);
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	// Initialize tokenizer for parsing main.
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 	initFieldChar(tk);
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 	// Now parse the attribute templates, but no template attributes.
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	parseAttributes(tk);
2187c478bd9Sstevel@tonic-gate     }
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate     //
2217c478bd9Sstevel@tonic-gate     // ServiceLocationAttributeVerifier interface implementation.
2227c478bd9Sstevel@tonic-gate     //
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate     /**
2257c478bd9Sstevel@tonic-gate      * Returns the SLP service type for which this is the verifier.
2267c478bd9Sstevel@tonic-gate      *
2277c478bd9Sstevel@tonic-gate      * @return The SLP service type name.
2287c478bd9Sstevel@tonic-gate      */
2297c478bd9Sstevel@tonic-gate 
getServiceType()2307c478bd9Sstevel@tonic-gate     public ServiceType getServiceType() {
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 	return serviceType;
2337c478bd9Sstevel@tonic-gate     }
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate     /**
2367c478bd9Sstevel@tonic-gate      * Returns the SLP language locale of this is the verifier.
2377c478bd9Sstevel@tonic-gate      *
2387c478bd9Sstevel@tonic-gate      * @return The SLP language locale.
2397c478bd9Sstevel@tonic-gate      */
2407c478bd9Sstevel@tonic-gate 
getLocale()2417c478bd9Sstevel@tonic-gate     public Locale getLocale() {
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	return locale;
2447c478bd9Sstevel@tonic-gate     }
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate     /**
2477c478bd9Sstevel@tonic-gate      * Returns the SLP version of this is the verifier.
2487c478bd9Sstevel@tonic-gate      *
2497c478bd9Sstevel@tonic-gate      * @return The SLP version.
2507c478bd9Sstevel@tonic-gate      */
2517c478bd9Sstevel@tonic-gate 
getVersion()2527c478bd9Sstevel@tonic-gate     public String getVersion() {
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	return version;
2557c478bd9Sstevel@tonic-gate     }
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate     /**
2587c478bd9Sstevel@tonic-gate      * Returns the SLP URL syntax of this is the verifier.
2597c478bd9Sstevel@tonic-gate      *
2607c478bd9Sstevel@tonic-gate      * @return The SLP URL syntax.
2617c478bd9Sstevel@tonic-gate      */
2627c478bd9Sstevel@tonic-gate 
getURLSyntax()2637c478bd9Sstevel@tonic-gate     public String getURLSyntax() {
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 	return URLSyntax;
2667c478bd9Sstevel@tonic-gate     }
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate     /**
2697c478bd9Sstevel@tonic-gate      * Returns the SLP description of this is the verifier.
2707c478bd9Sstevel@tonic-gate      *
2717c478bd9Sstevel@tonic-gate      * @return The SLP description.
2727c478bd9Sstevel@tonic-gate      */
2737c478bd9Sstevel@tonic-gate 
getDescription()2747c478bd9Sstevel@tonic-gate     public String getDescription() {
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 	return description;
2777c478bd9Sstevel@tonic-gate     }
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate     /**
2807c478bd9Sstevel@tonic-gate      * Returns the ServiceLocationAttributeDescriptor object for the
281*55fea89dSDan Cross      * attribute having the named id. IF no such attribute exists in the
2827c478bd9Sstevel@tonic-gate      * template, returns null. This method is primarily for GUI tools to
2837c478bd9Sstevel@tonic-gate      * display attribute information. Programmatic verification of attributes
2847c478bd9Sstevel@tonic-gate      * should use the verifyAttribute() method.
2857c478bd9Sstevel@tonic-gate      *
2867c478bd9Sstevel@tonic-gate      * @param attrId Id of attribute to return.
2877c478bd9Sstevel@tonic-gate      * @return The ServiceLocationAttributeDescriptor object corresponding
2887c478bd9Sstevel@tonic-gate      * 	     to the parameter, or null if none.
2897c478bd9Sstevel@tonic-gate      */
2907c478bd9Sstevel@tonic-gate 
291*55fea89dSDan Cross     public ServiceLocationAttributeDescriptor
getAttributeDescriptor(String attrId)2927c478bd9Sstevel@tonic-gate 	getAttributeDescriptor(String attrId) {
2937c478bd9Sstevel@tonic-gate 
294*55fea89dSDan Cross 	return
2957c478bd9Sstevel@tonic-gate 	    (ServiceLocationAttributeDescriptor)
2967c478bd9Sstevel@tonic-gate 	    attributeDescriptors.get(attrId.toLowerCase());
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate     }
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate     /**
3017c478bd9Sstevel@tonic-gate      * Returns an Enumeration of
3027c478bd9Sstevel@tonic-gate      * ServiceLocationAttributeDescriptors for the template. This method
3037c478bd9Sstevel@tonic-gate      * is primarily for GUI tools to display attribute information.
304*55fea89dSDan Cross      * Programmatic verification of attributes should use the
3057c478bd9Sstevel@tonic-gate      * verifyAttribute() method. Note that small memory implementations
3067c478bd9Sstevel@tonic-gate      * may want to implement the Enumeration so that attributes are
3077c478bd9Sstevel@tonic-gate      * parsed on demand rather than at creation time.
3087c478bd9Sstevel@tonic-gate      *
3097c478bd9Sstevel@tonic-gate      * @return A Dictionary with attribute id's as the keys and
310*55fea89dSDan Cross      *	      ServiceLocationAttributeDescriptor objects for the
3117c478bd9Sstevel@tonic-gate      *	      attributes as the values.
3127c478bd9Sstevel@tonic-gate      */
3137c478bd9Sstevel@tonic-gate 
getAttributeDescriptors()3147c478bd9Sstevel@tonic-gate     public Enumeration getAttributeDescriptors() {
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	return ((Hashtable)attributeDescriptors.clone()).elements();
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate     }
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate     /**
3217c478bd9Sstevel@tonic-gate      * Verify that the attribute parameter is a valid SLP attribute.
322*55fea89dSDan Cross      *
3237c478bd9Sstevel@tonic-gate      * @param attribute The ServiceLocationAttribute to be verified.
3247c478bd9Sstevel@tonic-gate      */
3257c478bd9Sstevel@tonic-gate 
verifyAttribute(ServiceLocationAttribute attribute)3267c478bd9Sstevel@tonic-gate     public void verifyAttribute(ServiceLocationAttribute attribute)
3277c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	String id = attribute.getId().toLowerCase();
330*55fea89dSDan Cross 	ServiceLocationAttributeDescriptor des =
3317c478bd9Sstevel@tonic-gate 	    (ServiceLocationAttributeDescriptor)attributeDescriptors.get(id);
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	if (des == null) {
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	    throw
3367c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
3377c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
3387c478bd9Sstevel@tonic-gate 				"template_no_attribute",
3397c478bd9Sstevel@tonic-gate 				new Object[] { id });
3407c478bd9Sstevel@tonic-gate 	}
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	String type = des.getValueType();
3447c478bd9Sstevel@tonic-gate 	Vector vals = attribute.getValues();
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	// If keyword, check that no values were specified.
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 	if (des.getIsKeyword()) {
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	    if (vals != null) {
3517c478bd9Sstevel@tonic-gate 		throw
3527c478bd9Sstevel@tonic-gate 		    new ServiceLocationException(
3537c478bd9Sstevel@tonic-gate 					 ServiceLocationException.PARSE_ERROR,
3547c478bd9Sstevel@tonic-gate 					 "template_not_null",
3557c478bd9Sstevel@tonic-gate 					 new Object[] { id });
3567c478bd9Sstevel@tonic-gate 	    }
3577c478bd9Sstevel@tonic-gate 	} else {
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	    int i, n;
360*55fea89dSDan Cross 
3617c478bd9Sstevel@tonic-gate 	    // Check that a values vector exists, and, if the attribute is
3627c478bd9Sstevel@tonic-gate 	    //  not multivalued, only one element is in it.
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	    if (vals == null) {
3657c478bd9Sstevel@tonic-gate 		throw
3667c478bd9Sstevel@tonic-gate 		    new ServiceLocationException(
3677c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
3687c478bd9Sstevel@tonic-gate 				"template_null",
3697c478bd9Sstevel@tonic-gate 				new Object[] { id });
3707c478bd9Sstevel@tonic-gate 
371*55fea89dSDan Cross 	    }
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	    n = vals.size();
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	    if (n > 1 && !des.getIsMultivalued()) {
3767c478bd9Sstevel@tonic-gate 		throw
3777c478bd9Sstevel@tonic-gate 		    new ServiceLocationException(
3787c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
3797c478bd9Sstevel@tonic-gate 				"template_not_multi",
3807c478bd9Sstevel@tonic-gate 				new Object[] { id });
3817c478bd9Sstevel@tonic-gate 	    }
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	    // Get allowed values.
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	    Vector av = null;
3867c478bd9Sstevel@tonic-gate 	    Enumeration en = des.getAllowedValues();
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	    if (en.hasMoreElements()) {
3897c478bd9Sstevel@tonic-gate 		av = new Vector();
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 		while (en.hasMoreElements()) {
3927c478bd9Sstevel@tonic-gate 		    Object v = en.nextElement();
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 		    // Lower case if string, convert to Opaque if byte array.
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 		    if (type.equals(JAVA_STRING_TYPE)) {
3977c478bd9Sstevel@tonic-gate 			v = ((String)v).toLowerCase();
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 		    } else if (type.equals(JAVA_OPAQUE_TYPE)) {
4007c478bd9Sstevel@tonic-gate 			v = new Opaque((byte[])v);
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 		    }
4037c478bd9Sstevel@tonic-gate 		    av.addElement(v);
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 		}
4067c478bd9Sstevel@tonic-gate 	    }
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	    // Check that the types of the values vector match the attribute
4097c478bd9Sstevel@tonic-gate 	    //  type. Also, if any allowed values, that attribute values
4107c478bd9Sstevel@tonic-gate 	    //  match.
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	    String attTypeName = des.getValueType();
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	    for (i = 0; i < n; i++) {
4157c478bd9Sstevel@tonic-gate 		Object val = vals.elementAt(i);
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 		String typeName = val.getClass().getName();
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 		if (!typeName.equals(attTypeName)) {
4207c478bd9Sstevel@tonic-gate 		    throw
4217c478bd9Sstevel@tonic-gate 			new ServiceLocationException(
4227c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
4237c478bd9Sstevel@tonic-gate 				"template_type_mismatch",
4247c478bd9Sstevel@tonic-gate 				new Object[] { id, typeName, attTypeName });
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 		}
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 		// Convert value for comparison, if necessary.
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 		if (type.equals(JAVA_STRING_TYPE)) {
4317c478bd9Sstevel@tonic-gate 		    val = ((String)val).toLowerCase();
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 		} else if (type.equals(JAVA_OPAQUE_TYPE)) {
4347c478bd9Sstevel@tonic-gate 		    val = new Opaque((byte[])val);
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 		}
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 		if (av != null && !av.contains(val)) {
4397c478bd9Sstevel@tonic-gate 		    throw
4407c478bd9Sstevel@tonic-gate 			new ServiceLocationException(
4417c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
4427c478bd9Sstevel@tonic-gate 				"template_not_allowed_value",
4437c478bd9Sstevel@tonic-gate 				new Object[] {id, val});
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 		}
4467c478bd9Sstevel@tonic-gate 	    }
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	}
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	// No way to verify `X' because that's a search property. We
4517c478bd9Sstevel@tonic-gate 	//  must verify `O' in the context of an attribute set.
4527c478bd9Sstevel@tonic-gate     }
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate     /**
4557c478bd9Sstevel@tonic-gate      * Verify that the set of registration attributes matches the
4567c478bd9Sstevel@tonic-gate      * required attributes for the service.
4577c478bd9Sstevel@tonic-gate      *
4587c478bd9Sstevel@tonic-gate      * @param attributeVector A Vector of ServiceLocationAttribute objects
4597c478bd9Sstevel@tonic-gate      *			     for the registration.
4607c478bd9Sstevel@tonic-gate      * @exception ServiceLocationException Thrown if the
4617c478bd9Sstevel@tonic-gate      *		 attribute set is not valid. The message contains information
4627c478bd9Sstevel@tonic-gate      *		 on the attribute name and problem.
4637c478bd9Sstevel@tonic-gate      */
4647c478bd9Sstevel@tonic-gate 
verifyRegistration(Vector attributeVector)4657c478bd9Sstevel@tonic-gate     public void verifyRegistration(Vector attributeVector)
4667c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	Assert.nonNullParameter(attributeVector, "attributeVector");
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	if (attributeVector.size() <= 0) {
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 	    // Check whether any attributes are required. If so, then
4747c478bd9Sstevel@tonic-gate 	    // there's an error.
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 	    Enumeration en = attributeDescriptors.elements();
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	    while (en.hasMoreElements()) {
4797c478bd9Sstevel@tonic-gate 		ServiceLocationAttributeDescriptor attDesc =
4807c478bd9Sstevel@tonic-gate 		    (ServiceLocationAttributeDescriptor)en.nextElement();
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 		if (!attDesc.getIsOptional()) {
4837c478bd9Sstevel@tonic-gate 
484*55fea89dSDan Cross 		    throw
4857c478bd9Sstevel@tonic-gate 			new ServiceLocationException(
4867c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
4877c478bd9Sstevel@tonic-gate 				"template_missing_required",
4887c478bd9Sstevel@tonic-gate 				new Object[] { attDesc.getId() });
4897c478bd9Sstevel@tonic-gate 		}
4907c478bd9Sstevel@tonic-gate 	    }
4917c478bd9Sstevel@tonic-gate 	} else {
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	    // Construct a hashtable of incoming objects, verifying them
4947c478bd9Sstevel@tonic-gate 	    // while doing so.
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 	    int i, n = attributeVector.size();
4977c478bd9Sstevel@tonic-gate 	    Hashtable incoming = new Hashtable();
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 	    for (i = 0; i < n; i++) {
5007c478bd9Sstevel@tonic-gate 		ServiceLocationAttribute attribute =
5017c478bd9Sstevel@tonic-gate 		    (ServiceLocationAttribute)attributeVector.elementAt(i);
5027c478bd9Sstevel@tonic-gate 		String id = attribute.getId().toLowerCase();
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 		// If we already have it, signal a duplicate.
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate 		if (incoming.get(id) != null) {
5077c478bd9Sstevel@tonic-gate 		    throw
5087c478bd9Sstevel@tonic-gate 			new ServiceLocationException(
5097c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
5107c478bd9Sstevel@tonic-gate 				"template_dup",
5117c478bd9Sstevel@tonic-gate 				new Object[] { attribute.getId() });
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 		}
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 		verifyAttribute(attribute);
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 		incoming.put(id, attribute);
5187c478bd9Sstevel@tonic-gate 	    }
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	    // Now check that all required attributes are present.
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	    Enumeration en = attributeDescriptors.elements();
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	    while (en.hasMoreElements()) {
5257c478bd9Sstevel@tonic-gate 		ServiceLocationAttributeDescriptor attDesc =
5267c478bd9Sstevel@tonic-gate 		    (ServiceLocationAttributeDescriptor)en.nextElement();
5277c478bd9Sstevel@tonic-gate 		String attrId = attDesc.getId();
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 		if (!attDesc.getIsOptional() &&
5307c478bd9Sstevel@tonic-gate 		    incoming.get(attrId.toLowerCase()) == null) {
5317c478bd9Sstevel@tonic-gate 
532*55fea89dSDan Cross 		    throw
5337c478bd9Sstevel@tonic-gate 			new ServiceLocationException(
5347c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
5357c478bd9Sstevel@tonic-gate 				"template_missing_required",
5367c478bd9Sstevel@tonic-gate 				new Object[] { attrId });
5377c478bd9Sstevel@tonic-gate 		}
5387c478bd9Sstevel@tonic-gate 	    }
5397c478bd9Sstevel@tonic-gate 	}
5407c478bd9Sstevel@tonic-gate 
541*55fea89dSDan Cross     }
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate     //
5447c478bd9Sstevel@tonic-gate     // Private implementation. This is the template attribute parser.
5457c478bd9Sstevel@tonic-gate     //
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate     //
5487c478bd9Sstevel@tonic-gate     // Tokenizer initializers.
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate     // Base initialization. Resets syntax tables, sets up EOL parsing,
5517c478bd9Sstevel@tonic-gate     //  and makes word case significant.
5527c478bd9Sstevel@tonic-gate 
initForBase(StreamTokenizer tk)5537c478bd9Sstevel@tonic-gate     private void initForBase(StreamTokenizer tk) {
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 	// Each part of an attribute production must specify which
5567c478bd9Sstevel@tonic-gate 	//  characters belong to words.
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	tk.resetSyntax();
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 	// Note that we have to make EOL be whitespace even if significant
5617c478bd9Sstevel@tonic-gate 	//  because otherwise the line number won't be correctly incremented.
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 	tk.whitespaceChars((int)'\n', (int)'\n');
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 	// Don't lower case tokens.
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	tk.lowerCaseMode(false);
5687c478bd9Sstevel@tonic-gate     }
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate     // Initialize those token characters that appear in all
5717c478bd9Sstevel@tonic-gate     //  productions.
5727c478bd9Sstevel@tonic-gate 
initCommonToken(StreamTokenizer tk)5737c478bd9Sstevel@tonic-gate     private void initCommonToken(StreamTokenizer tk) {
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 	// These characters are recognized as parts of tokens.
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'A', (int)'Z');
5787c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'a', (int)'z');
5797c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'0', (int)'9');
5807c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'&', (int)'&');
5817c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'*', (int)'*');
5827c478bd9Sstevel@tonic-gate 	tk.wordChars((int)':', (int)':');
5837c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'-', (int)'-');
5847c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'_', (int)'_');
5857c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'$', (int)'$');
5867c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'+', (int)'+');
5877c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'@', (int)'@');
5887c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'.', (int)'.');
5897c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'|', (int)'|');
5907c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'<', (int)'<');
5917c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'>', (int)'>');
5927c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'~', (int)'~');
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate     }
5957c478bd9Sstevel@tonic-gate 
596*55fea89dSDan Cross     // Initialize tokenizer for parsing attribute name,
597*55fea89dSDan Cross     // attribute type and flags,
5987c478bd9Sstevel@tonic-gate     // and for boolean initializer lists.
5997c478bd9Sstevel@tonic-gate 
initIdChar(StreamTokenizer tk)6007c478bd9Sstevel@tonic-gate     private void initIdChar(StreamTokenizer tk) {
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 	initForBase(tk);
6037c478bd9Sstevel@tonic-gate 	initCommonToken(tk);
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 	// Need backslash for escaping.
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'\\', (int)'\\');
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	// Attribute id, Type, flags, and boolean initialzers
6107c478bd9Sstevel@tonic-gate 	//  all ignore white space.
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 	tk.whitespaceChars((int)' ', (int)' ');
6137c478bd9Sstevel@tonic-gate 	tk.whitespaceChars((int)'\t', (int)'\t');
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 	// Attribute part won't view newline as being significant.
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate 	tk.eolIsSignificant(false);
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 	// Case is not folded.
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	tk.lowerCaseMode(false);
6227c478bd9Sstevel@tonic-gate     }
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate     // Initialize tokenizer for parsing service type name.
6257c478bd9Sstevel@tonic-gate     //  need to restrict characters.
6267c478bd9Sstevel@tonic-gate 
initSchemeIdChar(StreamTokenizer tk)6277c478bd9Sstevel@tonic-gate     private void initSchemeIdChar(StreamTokenizer tk) {
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 	initForBase(tk);
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'A', (int)'Z');
6327c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'a', (int)'z');
6337c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'0', (int)'9');
6347c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'-', (int)'-');
6357c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'+', (int)'+');
6367c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'.', (int)'.');  // allows naming authority.
6377c478bd9Sstevel@tonic-gate 	tk.wordChars((int)':', (int)':');  // for abstract and concrete type.
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate 	// Scheme name, type, flags, and boolean initialzers
6407c478bd9Sstevel@tonic-gate 	//  all ignore white space.
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	tk.whitespaceChars((int)' ', (int)' ');
6437c478bd9Sstevel@tonic-gate 	tk.whitespaceChars((int)'\t', (int)'\t');
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 	// Scheme part won't view newline as being significant.
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	tk.eolIsSignificant(false);
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate 	// Case is not folded.
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 	tk.lowerCaseMode(false);
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate     }
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate     // Initialize tokenizer for string list parsing.
6567c478bd9Sstevel@tonic-gate     //  Everything except '#' and ',' is recognized.
6577c478bd9Sstevel@tonic-gate     //  Note that whitespace is significant, but
6587c478bd9Sstevel@tonic-gate     //  EOL is ignored.
6597c478bd9Sstevel@tonic-gate 
initStringItemChar(StreamTokenizer tk)6607c478bd9Sstevel@tonic-gate     private void initStringItemChar(StreamTokenizer tk) {
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 	initForBase(tk);
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'\t', (int)'\t');
6657c478bd9Sstevel@tonic-gate 	tk.wordChars((int)' ', (int)'"');
6667c478bd9Sstevel@tonic-gate 	// '#' goes here
6677c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'$', (int)'+');
6687c478bd9Sstevel@tonic-gate 	// ',' goes here
6697c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'-', (int)'/');
6707c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'0', (int)'9');
6717c478bd9Sstevel@tonic-gate 	tk.wordChars((int)':', (int)':');
6727c478bd9Sstevel@tonic-gate 	// ';' goes here
6737c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'<', (int)'@');
6747c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'A', (int)'Z');
6757c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'[', (int)'`');
6767c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'a', (int)'z');
6777c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'{', (int)'~');
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 	// '%' is also reserved, but it is postprocessed
6807c478bd9Sstevel@tonic-gate 	// after the string is collected.
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	// Parse by lines to check when we've reached the end of the list.
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 	tk.whitespaceChars((int)'\r', (int)'\r');
6857c478bd9Sstevel@tonic-gate 	tk.whitespaceChars((int)'\n', (int)'\n');
6867c478bd9Sstevel@tonic-gate 	tk.eolIsSignificant(true);
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate     }
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate     // Initialize tokenizer for integer list parsing.
6917c478bd9Sstevel@tonic-gate 
initIntItemChar(StreamTokenizer tk)6927c478bd9Sstevel@tonic-gate     private void initIntItemChar(StreamTokenizer tk) {
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate 	initForBase(tk);
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'0', (int)'9');
6977c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'-', (int)'-');
698*55fea89dSDan Cross 	tk.wordChars((int)'+', (int)'+');
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	// Integer value list parsing ignores white space.
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	tk.whitespaceChars((int)' ', (int)' ');
7037c478bd9Sstevel@tonic-gate 	tk.whitespaceChars((int)'\t', (int)'\t');
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 	// Parse by lines so we can find the end.
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 	tk.whitespaceChars((int)'\r', (int)'\r');
7087c478bd9Sstevel@tonic-gate 	tk.whitespaceChars((int)'\n', (int)'\n');
7097c478bd9Sstevel@tonic-gate 	tk.eolIsSignificant(true);
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate     }
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate     // Boolean lists have same item syntax as scheme char.
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate     // Initialize main production parsing. The only
7167c478bd9Sstevel@tonic-gate     //  significant token character is <NL> because
7177c478bd9Sstevel@tonic-gate     //  parsing is done on a line-oriented basis.
7187c478bd9Sstevel@tonic-gate 
initFieldChar(StreamTokenizer tk)7197c478bd9Sstevel@tonic-gate     private void initFieldChar(StreamTokenizer tk) {
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 	initForBase(tk);
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'\t', (int)'\t');
7247c478bd9Sstevel@tonic-gate 	tk.wordChars((int)' ', (int)'/');
7257c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'0', (int)'9');
7267c478bd9Sstevel@tonic-gate 	tk.wordChars((int)':', (int)'@');
7277c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'A', (int)'Z');
7287c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'[', (int)'`');
7297c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'a', (int)'z');
7307c478bd9Sstevel@tonic-gate 	tk.wordChars((int)'{', (int)'~');
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 	tk.whitespaceChars((int)'\r', (int)'\r');
7337c478bd9Sstevel@tonic-gate 	tk.whitespaceChars((int)'\n', (int)'\n');
7347c478bd9Sstevel@tonic-gate 	tk.eolIsSignificant(true);
7357c478bd9Sstevel@tonic-gate     }
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate     //
7387c478bd9Sstevel@tonic-gate     // Parsing methods.
7397c478bd9Sstevel@tonic-gate     //
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate     // Parse a template from the tokenizer.
7427c478bd9Sstevel@tonic-gate 
parseTemplate(StreamTokenizer tk)743*55fea89dSDan Cross     private void parseTemplate(StreamTokenizer tk)
7447c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate 	// First parse past the template attributes.
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 	parseTemplateAttributes(tk);
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 	// Finally, parse the attributes.
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 	parseAttributes(tk);
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate     }
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate     // Parse the template attributes from the tokenizer.
7577c478bd9Sstevel@tonic-gate 
parseTemplateAttributes(StreamTokenizer tk)758*55fea89dSDan Cross     private void parseTemplateAttributes(StreamTokenizer tk)
7597c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
760*55fea89dSDan Cross 
7617c478bd9Sstevel@tonic-gate 	int found = 0;
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 	// Parse each of the template attributes. Note that we are parsing
7647c478bd9Sstevel@tonic-gate 	//  the attribute value assignments, not definitions.
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	try {
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 	    do {
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 		found = found | parseTemplateAttribute(tk, found);
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate 	    } while (found != TEMPLATE_FOUND);
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 	} catch (IOException ex) {
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 	    throw
7777c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
7787c478bd9Sstevel@tonic-gate 				ServiceLocationException.INTERNAL_SYSTEM_ERROR,
7797c478bd9Sstevel@tonic-gate 				"template_io_error",
7807c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
781*55fea89dSDan Cross 
7827c478bd9Sstevel@tonic-gate 	}
7837c478bd9Sstevel@tonic-gate     }
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate     // Parse a template attribute.
7867c478bd9Sstevel@tonic-gate 
parseTemplateAttribute(StreamTokenizer tk, int found)787*55fea89dSDan Cross     private int parseTemplateAttribute(StreamTokenizer tk, int found)
7887c478bd9Sstevel@tonic-gate 	throws ServiceLocationException, IOException {
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate 	// Get line including id and equals.
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 	int tt = tk.nextToken();
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	if (tt != StreamTokenizer.TT_WORD) {
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate 	    throw
7977c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
798*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
7997c478bd9Sstevel@tonic-gate 				"template_assign_error",
8007c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
8017c478bd9Sstevel@tonic-gate 	}
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate 	// Get tokenizer for id and potential value line.
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate 	StringReader rdr = new StringReader(tk.sval);
8067c478bd9Sstevel@tonic-gate 	StreamTokenizer stk = new StreamTokenizer(rdr);
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	initIdChar(stk);
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 	// Make sure newline is there.
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 	if ((tt = tk.nextToken()) == StreamTokenizer.TT_EOF) {
8137c478bd9Sstevel@tonic-gate 
814*55fea89dSDan Cross 	    throw
8157c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
816*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
8177c478bd9Sstevel@tonic-gate 				"template_end_error",
8187c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 	}
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate 	if (tt != StreamTokenizer.TT_EOL) {
8237c478bd9Sstevel@tonic-gate 
824*55fea89dSDan Cross 	    throw
8257c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
826*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
8277c478bd9Sstevel@tonic-gate 				"template_unk_token",
8287c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 	}
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate 	// Parse off id.
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 	if ((tt = stk.nextToken()) != StreamTokenizer.TT_WORD) {
8367c478bd9Sstevel@tonic-gate 
837*55fea89dSDan Cross 	    throw
8387c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
839*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
8407c478bd9Sstevel@tonic-gate 				"template_missing_id",
8417c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
8427c478bd9Sstevel@tonic-gate 	}
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate 	String id = stk.sval;
8457c478bd9Sstevel@tonic-gate 	boolean duplicate = false;
8467c478bd9Sstevel@tonic-gate 	int mask = 0;
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 	// Check for the equals.
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate 	if ((tt = stk.nextToken()) != TT_EQUALS) {
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 	    throw
8537c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
854*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
8557c478bd9Sstevel@tonic-gate 				"template_missing_eq ",
8567c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate 	}
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 	// Depending on the id, parse the rest.
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate 	if (id.equalsIgnoreCase(SLPTemplateRegistry.SERVICE_ATTR_ID)) {
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 	    if ((found & SERVICE_MASK) == 0) {
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate 		// Just need to parse off the service type.
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 		if ((tt = stk.nextToken()) != StreamTokenizer.TT_WORD) {
8697c478bd9Sstevel@tonic-gate 		    throw
8707c478bd9Sstevel@tonic-gate 			new ServiceLocationException(
871*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
8727c478bd9Sstevel@tonic-gate 				"template_srv_type_err",
8737c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
8747c478bd9Sstevel@tonic-gate 		}
8757c478bd9Sstevel@tonic-gate 
8767c478bd9Sstevel@tonic-gate 		// Check for characters which are not alphanumerics, + and -.
8777c478bd9Sstevel@tonic-gate 		//  Service type names are more heavily restricted.
8787c478bd9Sstevel@tonic-gate 
879*55fea89dSDan Cross 		StreamTokenizer sttk =
8807c478bd9Sstevel@tonic-gate 		    new StreamTokenizer(new StringReader(stk.sval));
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 		initSchemeIdChar(sttk);
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 		if (sttk.nextToken() != StreamTokenizer.TT_WORD ||
8857c478bd9Sstevel@tonic-gate 		    !stk.sval.equals(sttk.sval)) {
8867c478bd9Sstevel@tonic-gate 		    throw
8877c478bd9Sstevel@tonic-gate 			new ServiceLocationException(
888*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
8897c478bd9Sstevel@tonic-gate 				"template_srv_type_err",
8907c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate 		}
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate 		// Need to prefix with "serivce:".
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 		String typeName = sttk.sval;
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 		if (!typeName.startsWith(Defaults.SERVICE_PREFIX+":")) {
8997c478bd9Sstevel@tonic-gate 		    typeName = Defaults.SERVICE_PREFIX+":"+typeName;
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 		}
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 		// Set service type instance variable.
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate 		serviceType = new ServiceType(typeName);
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 		// Check for extra stuff.
9087c478bd9Sstevel@tonic-gate 
9097c478bd9Sstevel@tonic-gate 		if ((tt = stk.nextToken()) != StreamTokenizer.TT_EOF) {
9107c478bd9Sstevel@tonic-gate 		    throw
9117c478bd9Sstevel@tonic-gate 			new ServiceLocationException(
912*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
9137c478bd9Sstevel@tonic-gate 				"template_srv_type_err",
9147c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
9157c478bd9Sstevel@tonic-gate 		}
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 		mask = SERVICE_MASK;
9187c478bd9Sstevel@tonic-gate 	    } else {
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 		duplicate = true;
9217c478bd9Sstevel@tonic-gate 	    }
9227c478bd9Sstevel@tonic-gate 	} else if (id.equalsIgnoreCase(SLPTemplateRegistry.VERSION_ATTR_ID)) {
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate 	    if ((found & VERSION_MASK) == 0) {
9257c478bd9Sstevel@tonic-gate 
9267c478bd9Sstevel@tonic-gate 		// Just need to parse off the version number.
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 		if ((tt = stk.nextToken()) != StreamTokenizer.TT_WORD) {
9297c478bd9Sstevel@tonic-gate 		    throw
9307c478bd9Sstevel@tonic-gate 			new ServiceLocationException(
931*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
9327c478bd9Sstevel@tonic-gate 				"template_vers_err",
9337c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
9347c478bd9Sstevel@tonic-gate 		}
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate 		// Make sure it's a valid version number.
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 		String version = stk.sval;
9397c478bd9Sstevel@tonic-gate 
9407c478bd9Sstevel@tonic-gate 		if (version.indexOf(TT_PERIOD) == -1) {
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 		    throw
9437c478bd9Sstevel@tonic-gate 			new ServiceLocationException(
944*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
9457c478bd9Sstevel@tonic-gate 				"template_vers_mssing",
9467c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 		}
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 		try {
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate 		    new Float(version);
9537c478bd9Sstevel@tonic-gate 		} catch (NumberFormatException ex) {
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 		    throw
9567c478bd9Sstevel@tonic-gate 			new ServiceLocationException(
957*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
9587c478bd9Sstevel@tonic-gate 				"template_vers_err",
9597c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate 		}
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate 		this.version = version;
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate 		// Check for extra stuff.
9667c478bd9Sstevel@tonic-gate 
9677c478bd9Sstevel@tonic-gate 		if ((tt = stk.nextToken()) != StreamTokenizer.TT_EOF) {
9687c478bd9Sstevel@tonic-gate 		    throw
9697c478bd9Sstevel@tonic-gate 			new ServiceLocationException(
970*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
9717c478bd9Sstevel@tonic-gate 				"template_vers_err",
9727c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
9737c478bd9Sstevel@tonic-gate 		}
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 		mask = VERSION_MASK;
9767c478bd9Sstevel@tonic-gate 	    } else {
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 		duplicate = true;
9797c478bd9Sstevel@tonic-gate 	    }
9807c478bd9Sstevel@tonic-gate 	} else if (id.equalsIgnoreCase(
9817c478bd9Sstevel@tonic-gate 				SLPTemplateRegistry.DESCRIPTION_ATTR_ID)) {
9827c478bd9Sstevel@tonic-gate 
9837c478bd9Sstevel@tonic-gate 	    // Make sure there is nothing else on that line.
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 	    if (stk.nextToken() != StreamTokenizer.TT_EOF) {
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate 		throw
9887c478bd9Sstevel@tonic-gate 		    new ServiceLocationException(
989*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
9907c478bd9Sstevel@tonic-gate 				"template_attr_syntax",
9917c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
9927c478bd9Sstevel@tonic-gate 	    }
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate 	    if ((found & DESCRIPTION_MASK) == 0) {
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate 		// Need to continue parsing help text until we reach a blank
9977c478bd9Sstevel@tonic-gate 		// line.
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 		String helpText = "";
10007c478bd9Sstevel@tonic-gate 
10017c478bd9Sstevel@tonic-gate 		do {
1002*55fea89dSDan Cross 		    int ptt = tt;
10037c478bd9Sstevel@tonic-gate 		    tt = tk.nextToken();
10047c478bd9Sstevel@tonic-gate 
10057c478bd9Sstevel@tonic-gate 		    if (tt == StreamTokenizer.TT_WORD) {
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate 			helpText = helpText + tk.sval + "\n";
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate 		    } else if (tt == StreamTokenizer.TT_EOL) {
10107c478bd9Sstevel@tonic-gate 
10117c478bd9Sstevel@tonic-gate 			// If previous token was end of line, quit.
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 			if (ptt == StreamTokenizer.TT_EOL) {
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 			    // Store any text first.
10167c478bd9Sstevel@tonic-gate 
10177c478bd9Sstevel@tonic-gate 			    if (helpText.length() > 0) {
10187c478bd9Sstevel@tonic-gate 				description = helpText;
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate 			    }
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate 			    tk.pushBack();  // so same as above
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate 			    break;
10257c478bd9Sstevel@tonic-gate 			}
10267c478bd9Sstevel@tonic-gate 		    } else if (tt == StreamTokenizer.TT_EOF) {
1027*55fea89dSDan Cross 			throw
10287c478bd9Sstevel@tonic-gate 			    new ServiceLocationException(
1029*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
10307c478bd9Sstevel@tonic-gate 				"template_end_error",
10317c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 		    } else {
10347c478bd9Sstevel@tonic-gate 
1035*55fea89dSDan Cross 			throw
10367c478bd9Sstevel@tonic-gate 			    new ServiceLocationException(
1037*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
10387c478bd9Sstevel@tonic-gate 				"template_unk_token",
10397c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate 		    }
10427c478bd9Sstevel@tonic-gate 
10437c478bd9Sstevel@tonic-gate 		} while (true);
10447c478bd9Sstevel@tonic-gate 
10457c478bd9Sstevel@tonic-gate 		mask = DESCRIPTION_MASK;
10467c478bd9Sstevel@tonic-gate 	    } else {
10477c478bd9Sstevel@tonic-gate 
10487c478bd9Sstevel@tonic-gate 		duplicate = true;
10497c478bd9Sstevel@tonic-gate 	    }
10507c478bd9Sstevel@tonic-gate 	} else if (id.equalsIgnoreCase(
10517c478bd9Sstevel@tonic-gate 				SLPTemplateRegistry.SERVICE_URL_ATTR_ID)) {
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate 	    if ((found & URL_PATH_RULES_MASK) == 0) {
10547c478bd9Sstevel@tonic-gate 
10557c478bd9Sstevel@tonic-gate 		String serviceURLGrammer = "";
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate 		// Pull everything out of the rdr StringReader until empty.
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 		int ic;
10607c478bd9Sstevel@tonic-gate 
10617c478bd9Sstevel@tonic-gate 		while ((ic = rdr.read()) != -1) {
10627c478bd9Sstevel@tonic-gate 		    serviceURLGrammer += (char)ic;
10637c478bd9Sstevel@tonic-gate 
10647c478bd9Sstevel@tonic-gate 		}
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate 		serviceURLGrammer += "\n";
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 		// Need to continue parsing service URL syntax until we
10697c478bd9Sstevel@tonic-gate 		// reach a blank line.
10707c478bd9Sstevel@tonic-gate 
1071*55fea89dSDan Cross 		tt = StreamTokenizer.TT_EOL;
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate 		do {
10747c478bd9Sstevel@tonic-gate 		    int ptt = tt;
10757c478bd9Sstevel@tonic-gate 		    tt = tk.nextToken();
10767c478bd9Sstevel@tonic-gate 
10777c478bd9Sstevel@tonic-gate 		    if (tt == StreamTokenizer.TT_WORD) {
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate 			serviceURLGrammer = serviceURLGrammer + tk.sval + "\n";
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate 		    } else if (tt == StreamTokenizer.TT_EOL) {
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 			// If previous token was end of line, quit.
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate 			if (ptt == StreamTokenizer.TT_EOL) {
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate 			    // Store any text first.
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate 			    if (serviceURLGrammer.length() > 0) {
10907c478bd9Sstevel@tonic-gate 				URLSyntax = serviceURLGrammer;
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate 			    }
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate 			    tk.pushBack();  // so same as above.
10957c478bd9Sstevel@tonic-gate 
10967c478bd9Sstevel@tonic-gate 			    break;
10977c478bd9Sstevel@tonic-gate 			}
10987c478bd9Sstevel@tonic-gate 		    } else if (tt == StreamTokenizer.TT_EOF) {
1099*55fea89dSDan Cross 			throw
11007c478bd9Sstevel@tonic-gate 			    new ServiceLocationException(
1101*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
11027c478bd9Sstevel@tonic-gate 				"template_end_error",
11037c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate 		    } else {
11067c478bd9Sstevel@tonic-gate 
1107*55fea89dSDan Cross 			throw
11087c478bd9Sstevel@tonic-gate 			    new ServiceLocationException(
1109*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
11107c478bd9Sstevel@tonic-gate 				"template_unk_token",
11117c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate 		    }
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate 		} while (true);
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 		mask = URL_PATH_RULES_MASK;
11187c478bd9Sstevel@tonic-gate 	    } else {
11197c478bd9Sstevel@tonic-gate 
11207c478bd9Sstevel@tonic-gate 		duplicate = true;
11217c478bd9Sstevel@tonic-gate 	    }
11227c478bd9Sstevel@tonic-gate 	} else {
11237c478bd9Sstevel@tonic-gate 
11247c478bd9Sstevel@tonic-gate 	    throw
11257c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
1126*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
11277c478bd9Sstevel@tonic-gate 				"template_nontattribute_err",
11287c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate 	}
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 	// Throw exception if a duplicate definition was detected.
11337c478bd9Sstevel@tonic-gate 
11347c478bd9Sstevel@tonic-gate 	if (duplicate) {
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate 	    throw
11377c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
1138*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
11397c478bd9Sstevel@tonic-gate 				"template_dup_def",
11407c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate 	}
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate 
11457c478bd9Sstevel@tonic-gate 	// Make sure the assignment ends with a blank line.
11467c478bd9Sstevel@tonic-gate 
11477c478bd9Sstevel@tonic-gate 	if ((tt = tk.nextToken()) != StreamTokenizer.TT_EOL) {
11487c478bd9Sstevel@tonic-gate 
11497c478bd9Sstevel@tonic-gate 	    throw
11507c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
1151*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
11527c478bd9Sstevel@tonic-gate 				"template_attr_syntax",
11537c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
11547c478bd9Sstevel@tonic-gate 
11557c478bd9Sstevel@tonic-gate 	}
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate 	return mask;
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate     }
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate 
11627c478bd9Sstevel@tonic-gate     // Parse the attributes from the tokenizer.
11637c478bd9Sstevel@tonic-gate 
parseAttributes(StreamTokenizer tk)1164*55fea89dSDan Cross     private void parseAttributes(StreamTokenizer tk)
11657c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
11667c478bd9Sstevel@tonic-gate 
11677c478bd9Sstevel@tonic-gate 	try {
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate 	    do {
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate 		// Check if at end of file yet.
11727c478bd9Sstevel@tonic-gate 
11737c478bd9Sstevel@tonic-gate 		int tt = tk.nextToken();
11747c478bd9Sstevel@tonic-gate 
11757c478bd9Sstevel@tonic-gate 		if (tt == StreamTokenizer.TT_EOF) {
11767c478bd9Sstevel@tonic-gate 		    break;
11777c478bd9Sstevel@tonic-gate 		}
11787c478bd9Sstevel@tonic-gate 
11797c478bd9Sstevel@tonic-gate 		// If not, push token back so we can get it next time.
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate 		tk.pushBack();
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate 		// Parse off the attribute descriptor.
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate 		AttributeDescriptor attDesc = parseAttribute(tk);
11867c478bd9Sstevel@tonic-gate 
11877c478bd9Sstevel@tonic-gate 		// Check whether default values, if any, are correct.
11887c478bd9Sstevel@tonic-gate 
11897c478bd9Sstevel@tonic-gate 		checkDefaultValues(attDesc);
11907c478bd9Sstevel@tonic-gate 
11917c478bd9Sstevel@tonic-gate 		// If the attribute already exists, then throw exception.
11927c478bd9Sstevel@tonic-gate 		//  We could arguably replace existing, but it might
11937c478bd9Sstevel@tonic-gate 		//  suprise the user.
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate 		String attrId = attDesc.getId().toLowerCase();
11967c478bd9Sstevel@tonic-gate 
11977c478bd9Sstevel@tonic-gate 		if (attributeDescriptors.get(attrId) != null) {
11987c478bd9Sstevel@tonic-gate 
1199*55fea89dSDan Cross 		    throw
12007c478bd9Sstevel@tonic-gate 			new ServiceLocationException(
1201*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
12027c478bd9Sstevel@tonic-gate 				"template_dup_def",
12037c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate 		}
12067c478bd9Sstevel@tonic-gate 
12077c478bd9Sstevel@tonic-gate 		// Add the attribute to the descriptor table.
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate 		attributeDescriptors.put(attrId, attDesc);
12107c478bd9Sstevel@tonic-gate 
12117c478bd9Sstevel@tonic-gate 	    } while (true);
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate 	} catch (IOException ex) {
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 	    throw
12167c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
12177c478bd9Sstevel@tonic-gate 				ServiceLocationException.INTERNAL_SYSTEM_ERROR,
12187c478bd9Sstevel@tonic-gate 				"template_io_error",
12197c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
12207c478bd9Sstevel@tonic-gate 	}
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate     }
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate     // Parse a single attribute description from the tokenizer.
12257c478bd9Sstevel@tonic-gate 
1226*55fea89dSDan Cross     private AttributeDescriptor
parseAttribute(StreamTokenizer tk)12277c478bd9Sstevel@tonic-gate 	parseAttribute(StreamTokenizer tk) throws ServiceLocationException {
12287c478bd9Sstevel@tonic-gate 
12297c478bd9Sstevel@tonic-gate 	AttributeDescriptor attDesc = new AttributeDescriptor();
12307c478bd9Sstevel@tonic-gate 	int lineno = 0;
12317c478bd9Sstevel@tonic-gate 
12327c478bd9Sstevel@tonic-gate 	try {
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate 	    // Parse the string for attribute id, type, and flags.
12357c478bd9Sstevel@tonic-gate 
12367c478bd9Sstevel@tonic-gate 	    lineno = tk.lineno();
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate 	    int tt = tk.nextToken();
12397c478bd9Sstevel@tonic-gate 
12407c478bd9Sstevel@tonic-gate 	    if (tt != StreamTokenizer.TT_WORD) {
12417c478bd9Sstevel@tonic-gate 		throw
12427c478bd9Sstevel@tonic-gate 		    new ServiceLocationException(
12437c478bd9Sstevel@tonic-gate 				ServiceLocationException.PARSE_ERROR,
12447c478bd9Sstevel@tonic-gate 				"template_attr_syntax",
12457c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
12467c478bd9Sstevel@tonic-gate 	    }
12477c478bd9Sstevel@tonic-gate 
1248*55fea89dSDan Cross 	    StreamTokenizer stk =
12497c478bd9Sstevel@tonic-gate 		new StreamTokenizer(new StringReader(tk.sval));
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate 	    initIdChar(stk);
12527c478bd9Sstevel@tonic-gate 
12537c478bd9Sstevel@tonic-gate 	    // Parse the attribute id.
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate 	    parseId(stk, attDesc, lineno);
1256*55fea89dSDan Cross 
12577c478bd9Sstevel@tonic-gate 	    // Parse the type and flags.
12587c478bd9Sstevel@tonic-gate 
12597c478bd9Sstevel@tonic-gate 	    parseTypeAndFlags(stk, attDesc, lineno);
12607c478bd9Sstevel@tonic-gate 
12617c478bd9Sstevel@tonic-gate 	    tt = tk.nextToken();
12627c478bd9Sstevel@tonic-gate 
12637c478bd9Sstevel@tonic-gate 	    if (tt == StreamTokenizer.TT_EOF) {
12647c478bd9Sstevel@tonic-gate 
1265*55fea89dSDan Cross 		throw
12667c478bd9Sstevel@tonic-gate 		    new ServiceLocationException(
1267*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
12687c478bd9Sstevel@tonic-gate 				"template_end_error",
12697c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate 	    }
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate 	    if (tt != StreamTokenizer.TT_EOL) {
12747c478bd9Sstevel@tonic-gate 
1275*55fea89dSDan Cross 		throw
12767c478bd9Sstevel@tonic-gate 		    new ServiceLocationException(
1277*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
12787c478bd9Sstevel@tonic-gate 				"template_unk_token",
12797c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
12807c478bd9Sstevel@tonic-gate 
12817c478bd9Sstevel@tonic-gate 	    }
12827c478bd9Sstevel@tonic-gate 
12837c478bd9Sstevel@tonic-gate 	    // Parse initial values.
12847c478bd9Sstevel@tonic-gate 
12857c478bd9Sstevel@tonic-gate 	    if (!attDesc.getIsKeyword()) {
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate 		String tok = "";
12887c478bd9Sstevel@tonic-gate 
12897c478bd9Sstevel@tonic-gate 		// Read in entire list.
12907c478bd9Sstevel@tonic-gate 
12917c478bd9Sstevel@tonic-gate 		do {
12927c478bd9Sstevel@tonic-gate 		    int ptt = tt;
12937c478bd9Sstevel@tonic-gate 		    lineno = tk.lineno();
12947c478bd9Sstevel@tonic-gate 		    tt = tk.nextToken();
12957c478bd9Sstevel@tonic-gate 
12967c478bd9Sstevel@tonic-gate 		    if (tt == StreamTokenizer.TT_WORD) {
12977c478bd9Sstevel@tonic-gate 
12987c478bd9Sstevel@tonic-gate 			// Trim line, check for '#', indicating end of list.
12997c478bd9Sstevel@tonic-gate 
13007c478bd9Sstevel@tonic-gate 			String line = tk.sval.trim();
13017c478bd9Sstevel@tonic-gate 
13027c478bd9Sstevel@tonic-gate 			if (line.charAt(0) == TT_FIELD) {
13037c478bd9Sstevel@tonic-gate 			    // it's help text already.
13047c478bd9Sstevel@tonic-gate 
13057c478bd9Sstevel@tonic-gate 			    if (tok.length() > 0) {
13067c478bd9Sstevel@tonic-gate 				stk =
13077c478bd9Sstevel@tonic-gate 				    new StreamTokenizer(new StringReader(tok));
13087c478bd9Sstevel@tonic-gate 				parseDefaultValues(stk, attDesc, lineno);
13097c478bd9Sstevel@tonic-gate 			    }
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate 			    tk.pushBack();
13127c478bd9Sstevel@tonic-gate 			    break;
13137c478bd9Sstevel@tonic-gate 
13147c478bd9Sstevel@tonic-gate 			} else {
13157c478bd9Sstevel@tonic-gate 
13167c478bd9Sstevel@tonic-gate 			    // Otherwise concatenate onto growing list.
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 			    tok = tok + line;
13197c478bd9Sstevel@tonic-gate 
13207c478bd9Sstevel@tonic-gate 			}
13217c478bd9Sstevel@tonic-gate 
1322*55fea89dSDan Cross 		    } else if (tt == StreamTokenizer.TT_EOL) {
13237c478bd9Sstevel@tonic-gate 
13247c478bd9Sstevel@tonic-gate 			if (ptt == StreamTokenizer.TT_EOL) {
13257c478bd9Sstevel@tonic-gate 			    // end of attribute definition.
13267c478bd9Sstevel@tonic-gate 
13277c478bd9Sstevel@tonic-gate 			    // Process any accumulated list.
13287c478bd9Sstevel@tonic-gate 
13297c478bd9Sstevel@tonic-gate 			    if (tok.length() > 0) {
13307c478bd9Sstevel@tonic-gate 				stk =
13317c478bd9Sstevel@tonic-gate 				    new StreamTokenizer(new StringReader(tok));
13327c478bd9Sstevel@tonic-gate 				parseDefaultValues(stk, attDesc, lineno);
13337c478bd9Sstevel@tonic-gate 			    }
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate 			    return attDesc;
13367c478bd9Sstevel@tonic-gate 
13377c478bd9Sstevel@tonic-gate 			}
13387c478bd9Sstevel@tonic-gate 		    } else if (tt == StreamTokenizer.TT_EOF) {
1339*55fea89dSDan Cross 			throw
13407c478bd9Sstevel@tonic-gate 			    new ServiceLocationException(
1341*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
13427c478bd9Sstevel@tonic-gate 				"template_end_error",
13437c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
13447c478bd9Sstevel@tonic-gate 
13457c478bd9Sstevel@tonic-gate 		    } else {
13467c478bd9Sstevel@tonic-gate 
1347*55fea89dSDan Cross 			throw
13487c478bd9Sstevel@tonic-gate 			    new ServiceLocationException(
1349*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
13507c478bd9Sstevel@tonic-gate 				"template_unk_token",
13517c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate 		    }
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate 		} while (true);
13567c478bd9Sstevel@tonic-gate 
13577c478bd9Sstevel@tonic-gate 	    } else {
13587c478bd9Sstevel@tonic-gate 		attDesc.setDefaultValues(null);
13597c478bd9Sstevel@tonic-gate 		attDesc.setAllowedValues(null);
13607c478bd9Sstevel@tonic-gate 
13617c478bd9Sstevel@tonic-gate 		// Check for end of definition.
13627c478bd9Sstevel@tonic-gate 
13637c478bd9Sstevel@tonic-gate 		if ((tt = tk.nextToken()) == StreamTokenizer.TT_EOL) {
13647c478bd9Sstevel@tonic-gate 		    return attDesc;
13657c478bd9Sstevel@tonic-gate 
13667c478bd9Sstevel@tonic-gate 		} else if (tt == StreamTokenizer.TT_WORD) {
13677c478bd9Sstevel@tonic-gate 
13687c478bd9Sstevel@tonic-gate 		    // Check for start of help text.
13697c478bd9Sstevel@tonic-gate 
13707c478bd9Sstevel@tonic-gate 		    String line = tk.sval.trim();
1371*55fea89dSDan Cross 
13727c478bd9Sstevel@tonic-gate 		    if (line.charAt(0) != TT_FIELD) {
13737c478bd9Sstevel@tonic-gate 			throw
13747c478bd9Sstevel@tonic-gate 			    new ServiceLocationException(
1375*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
13767c478bd9Sstevel@tonic-gate 				"template_attr_syntax",
13777c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
13787c478bd9Sstevel@tonic-gate 
13797c478bd9Sstevel@tonic-gate 		    } else {
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate 			tk.pushBack();
13827c478bd9Sstevel@tonic-gate 
13837c478bd9Sstevel@tonic-gate 		    }
13847c478bd9Sstevel@tonic-gate 
13857c478bd9Sstevel@tonic-gate 		} else if (tt == StreamTokenizer.TT_EOF) {
1386*55fea89dSDan Cross 		    throw
13877c478bd9Sstevel@tonic-gate 			new ServiceLocationException(
1388*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
13897c478bd9Sstevel@tonic-gate 				"template_end_error",
13907c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
13917c478bd9Sstevel@tonic-gate 
13927c478bd9Sstevel@tonic-gate 		} else {
13937c478bd9Sstevel@tonic-gate 
1394*55fea89dSDan Cross 		    throw
13957c478bd9Sstevel@tonic-gate 			new ServiceLocationException(
1396*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
13977c478bd9Sstevel@tonic-gate 				"template_unk_token",
13987c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
13997c478bd9Sstevel@tonic-gate 
14007c478bd9Sstevel@tonic-gate 		}
14017c478bd9Sstevel@tonic-gate 	    }
14027c478bd9Sstevel@tonic-gate 
14037c478bd9Sstevel@tonic-gate 
14047c478bd9Sstevel@tonic-gate 	    // Parse help text.
14057c478bd9Sstevel@tonic-gate 
14067c478bd9Sstevel@tonic-gate 	    String helpText = "";
14077c478bd9Sstevel@tonic-gate 
14087c478bd9Sstevel@tonic-gate 	    do {
1409*55fea89dSDan Cross 		int ptt = tt;
14107c478bd9Sstevel@tonic-gate 		lineno = tk.lineno();
14117c478bd9Sstevel@tonic-gate 		tt = tk.nextToken();
14127c478bd9Sstevel@tonic-gate 
14137c478bd9Sstevel@tonic-gate 		if (tt == StreamTokenizer.TT_WORD) {
14147c478bd9Sstevel@tonic-gate 
14157c478bd9Sstevel@tonic-gate 		    // Check for end of help text.
14167c478bd9Sstevel@tonic-gate 
14177c478bd9Sstevel@tonic-gate 		    String line = tk.sval.trim();
1418*55fea89dSDan Cross 
14197c478bd9Sstevel@tonic-gate 		    if (line.charAt(0) == TT_FIELD) {
14207c478bd9Sstevel@tonic-gate 
14217c478bd9Sstevel@tonic-gate 			// Help text is collected verbatim after '#'.
14227c478bd9Sstevel@tonic-gate 
1423*55fea89dSDan Cross 			helpText =
14247c478bd9Sstevel@tonic-gate 			    helpText + line.substring(1) + "\n";
14257c478bd9Sstevel@tonic-gate 
14267c478bd9Sstevel@tonic-gate 		    } else {
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate 			// We've reached the end of the help text. Store it
14297c478bd9Sstevel@tonic-gate 			//  and break out of the loop.
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate 			if (helpText.length() > 0) {
14327c478bd9Sstevel@tonic-gate 			    attDesc.setDescription(helpText);
14337c478bd9Sstevel@tonic-gate 			}
14347c478bd9Sstevel@tonic-gate 
14357c478bd9Sstevel@tonic-gate 			tk.pushBack();
14367c478bd9Sstevel@tonic-gate 			break;
14377c478bd9Sstevel@tonic-gate 
14387c478bd9Sstevel@tonic-gate 		    }
14397c478bd9Sstevel@tonic-gate 
14407c478bd9Sstevel@tonic-gate 		} else if (tt == StreamTokenizer.TT_EOL ||
14417c478bd9Sstevel@tonic-gate 			   tt == StreamTokenizer.TT_EOF) {
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate 		    // If previous token was end of line, quit.
14447c478bd9Sstevel@tonic-gate 
14457c478bd9Sstevel@tonic-gate 		    if (ptt == StreamTokenizer.TT_EOL) {
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate 			// Store any text first.
14487c478bd9Sstevel@tonic-gate 
14497c478bd9Sstevel@tonic-gate 			if (helpText.length() > 0) {
14507c478bd9Sstevel@tonic-gate 			    attDesc.setDescription(helpText);
14517c478bd9Sstevel@tonic-gate 			}
14527c478bd9Sstevel@tonic-gate 
14537c478bd9Sstevel@tonic-gate 			// If this is a keyword attribute, set the allowed
14547c478bd9Sstevel@tonic-gate 			//  values list to null.
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate 			if (attDesc.getIsKeyword()) {
14577c478bd9Sstevel@tonic-gate 			    attDesc.setAllowedValues(null);
14587c478bd9Sstevel@tonic-gate 			}
14597c478bd9Sstevel@tonic-gate 
14607c478bd9Sstevel@tonic-gate 			return attDesc;
14617c478bd9Sstevel@tonic-gate 
14627c478bd9Sstevel@tonic-gate 		    } else if (tt == StreamTokenizer.TT_EOF) {
14637c478bd9Sstevel@tonic-gate 
14647c478bd9Sstevel@tonic-gate 			// Error if previous token wasn't EOL.
14657c478bd9Sstevel@tonic-gate 
1466*55fea89dSDan Cross 			throw
14677c478bd9Sstevel@tonic-gate 			    new ServiceLocationException(
1468*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
14697c478bd9Sstevel@tonic-gate 				"template_end_error",
14707c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
14717c478bd9Sstevel@tonic-gate 		    }
14727c478bd9Sstevel@tonic-gate 
14737c478bd9Sstevel@tonic-gate 		} else {
14747c478bd9Sstevel@tonic-gate 
1475*55fea89dSDan Cross 		    throw
14767c478bd9Sstevel@tonic-gate 			new ServiceLocationException(
1477*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
14787c478bd9Sstevel@tonic-gate 				"template_unk_token",
14797c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
14807c478bd9Sstevel@tonic-gate 		}
14817c478bd9Sstevel@tonic-gate 
14827c478bd9Sstevel@tonic-gate 	    } while (true);
14837c478bd9Sstevel@tonic-gate 
14847c478bd9Sstevel@tonic-gate 	    // Parse allowed values.
14857c478bd9Sstevel@tonic-gate 
14867c478bd9Sstevel@tonic-gate 	    if (!attDesc.getIsKeyword()) {
14877c478bd9Sstevel@tonic-gate 
14887c478bd9Sstevel@tonic-gate 		String tok = "";
14897c478bd9Sstevel@tonic-gate 
14907c478bd9Sstevel@tonic-gate 		// Read in entire list.
14917c478bd9Sstevel@tonic-gate 
14927c478bd9Sstevel@tonic-gate 		do {
14937c478bd9Sstevel@tonic-gate 		    int ptt = tt;
14947c478bd9Sstevel@tonic-gate 		    lineno = tk.lineno();
14957c478bd9Sstevel@tonic-gate 		    tt = tk.nextToken();
14967c478bd9Sstevel@tonic-gate 
14977c478bd9Sstevel@tonic-gate 		    if (tt == StreamTokenizer.TT_WORD) {
14987c478bd9Sstevel@tonic-gate 
14997c478bd9Sstevel@tonic-gate 			// Concatenate onto growing list.
15007c478bd9Sstevel@tonic-gate 
15017c478bd9Sstevel@tonic-gate 			tok = tok + tk.sval;
15027c478bd9Sstevel@tonic-gate 
1503*55fea89dSDan Cross 		    } else if (tt == StreamTokenizer.TT_EOL) {
15047c478bd9Sstevel@tonic-gate 
15057c478bd9Sstevel@tonic-gate 			if (ptt == StreamTokenizer.TT_EOL) {
15067c478bd9Sstevel@tonic-gate 			    // end of attribute definition.
15077c478bd9Sstevel@tonic-gate 
15087c478bd9Sstevel@tonic-gate 			    // Process any accumulated list.
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate 			    if (tok.length() > 0) {
15117c478bd9Sstevel@tonic-gate 				stk =
15127c478bd9Sstevel@tonic-gate 				    new StreamTokenizer(new StringReader(tok));
15137c478bd9Sstevel@tonic-gate 				parseAllowedValues(stk, attDesc, lineno);
15147c478bd9Sstevel@tonic-gate 			    }
15157c478bd9Sstevel@tonic-gate 
15167c478bd9Sstevel@tonic-gate 			    return attDesc;
15177c478bd9Sstevel@tonic-gate 
15187c478bd9Sstevel@tonic-gate 			}
15197c478bd9Sstevel@tonic-gate 		    } else if (tt == StreamTokenizer.TT_EOF) {
1520*55fea89dSDan Cross 			throw
15217c478bd9Sstevel@tonic-gate 			    new ServiceLocationException(
1522*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
15237c478bd9Sstevel@tonic-gate 				"template_end_error",
15247c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
15257c478bd9Sstevel@tonic-gate 
15267c478bd9Sstevel@tonic-gate 		    } else {
15277c478bd9Sstevel@tonic-gate 
15287c478bd9Sstevel@tonic-gate 			throw
15297c478bd9Sstevel@tonic-gate 			    new ServiceLocationException(
1530*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
15317c478bd9Sstevel@tonic-gate 				"template_unk_token",
15327c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
15337c478bd9Sstevel@tonic-gate 		    }
15347c478bd9Sstevel@tonic-gate 
15357c478bd9Sstevel@tonic-gate 		} while (true);
15367c478bd9Sstevel@tonic-gate 
15377c478bd9Sstevel@tonic-gate 	    } else {
15387c478bd9Sstevel@tonic-gate 
15397c478bd9Sstevel@tonic-gate 		// Error. Keyword attribute should have ended during help text
15407c478bd9Sstevel@tonic-gate 		//  parsing or before.
1541*55fea89dSDan Cross 
15427c478bd9Sstevel@tonic-gate 		throw
15437c478bd9Sstevel@tonic-gate 		    new ServiceLocationException(
1544*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
15457c478bd9Sstevel@tonic-gate 				"template_attr_syntax",
15467c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(tk.lineno())});
15477c478bd9Sstevel@tonic-gate 	    }
15487c478bd9Sstevel@tonic-gate 
15497c478bd9Sstevel@tonic-gate 	} catch (IOException ex) {
15507c478bd9Sstevel@tonic-gate 
15517c478bd9Sstevel@tonic-gate 	    throw
15527c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
15537c478bd9Sstevel@tonic-gate 				ServiceLocationException.INTERNAL_SYSTEM_ERROR,
15547c478bd9Sstevel@tonic-gate 				"template_io_error",
15557c478bd9Sstevel@tonic-gate 				new Object[] {
1556*55fea89dSDan Cross 		    Integer.toString(tk.lineno()),
15577c478bd9Sstevel@tonic-gate 			ex.getMessage()});
15587c478bd9Sstevel@tonic-gate 	}
15597c478bd9Sstevel@tonic-gate 
15607c478bd9Sstevel@tonic-gate     }
15617c478bd9Sstevel@tonic-gate 
15627c478bd9Sstevel@tonic-gate     // Check whether the default values, if any, are correct.
15637c478bd9Sstevel@tonic-gate 
checkDefaultValues(AttributeDescriptor attDesc)1564*55fea89dSDan Cross     private void checkDefaultValues(AttributeDescriptor attDesc)
15657c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
15667c478bd9Sstevel@tonic-gate 
15677c478bd9Sstevel@tonic-gate 	// Don't bother if it's a keyword attribute, parsing has checked.
15687c478bd9Sstevel@tonic-gate 
15697c478bd9Sstevel@tonic-gate 	if (attDesc.getIsKeyword()) {
15707c478bd9Sstevel@tonic-gate 	    return;
15717c478bd9Sstevel@tonic-gate 	}
15727c478bd9Sstevel@tonic-gate 
15737c478bd9Sstevel@tonic-gate 	Enumeration init = attDesc.getDefaultValues();
15747c478bd9Sstevel@tonic-gate 	Enumeration en = attDesc.getAllowedValues();
15757c478bd9Sstevel@tonic-gate 	Vector allowed = new Vector();
15767c478bd9Sstevel@tonic-gate 	String attDescType = attDesc.getValueType();
15777c478bd9Sstevel@tonic-gate 
15787c478bd9Sstevel@tonic-gate 	// First, collect the allowed values.
15797c478bd9Sstevel@tonic-gate 
15807c478bd9Sstevel@tonic-gate 	while (en.hasMoreElements()) {
15817c478bd9Sstevel@tonic-gate 	    Object allval = en.nextElement();
15827c478bd9Sstevel@tonic-gate 
15837c478bd9Sstevel@tonic-gate 	    // Lower case strings and create opaques for comparison
15847c478bd9Sstevel@tonic-gate 	    // if type is opaque.
15857c478bd9Sstevel@tonic-gate 
15867c478bd9Sstevel@tonic-gate 	    if (attDescType.equals(JAVA_STRING_TYPE)) {
15877c478bd9Sstevel@tonic-gate 		allval = ((String)allval).toLowerCase();
15887c478bd9Sstevel@tonic-gate 
15897c478bd9Sstevel@tonic-gate 	    } else if (attDescType.equals(JAVA_OPAQUE_TYPE)) {
15907c478bd9Sstevel@tonic-gate 		allval = new Opaque((byte[])allval);
15917c478bd9Sstevel@tonic-gate 
15927c478bd9Sstevel@tonic-gate 	    }
15937c478bd9Sstevel@tonic-gate 
15947c478bd9Sstevel@tonic-gate 	    allowed.addElement(allval);
15957c478bd9Sstevel@tonic-gate 	}
15967c478bd9Sstevel@tonic-gate 
15977c478bd9Sstevel@tonic-gate 	// Now compare the allowed with the initial.
15987c478bd9Sstevel@tonic-gate 
15997c478bd9Sstevel@tonic-gate 	if (allowed.size() > 0) {
16007c478bd9Sstevel@tonic-gate 
16017c478bd9Sstevel@tonic-gate 	    // Error if allowed is restricted but no initializers.
16027c478bd9Sstevel@tonic-gate 
16037c478bd9Sstevel@tonic-gate 	    if (!init.hasMoreElements()) {
16047c478bd9Sstevel@tonic-gate 
16057c478bd9Sstevel@tonic-gate 		throw
16067c478bd9Sstevel@tonic-gate 		    new ServiceLocationException(
1607*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
16087c478bd9Sstevel@tonic-gate 				"template_no_init",
16097c478bd9Sstevel@tonic-gate 				new Object[] {attDesc.getId()});
16107c478bd9Sstevel@tonic-gate 
16117c478bd9Sstevel@tonic-gate 	    }
16127c478bd9Sstevel@tonic-gate 
16137c478bd9Sstevel@tonic-gate 	    Object val = null;
16147c478bd9Sstevel@tonic-gate 
16157c478bd9Sstevel@tonic-gate 	    // Compare init values with allowed.
16167c478bd9Sstevel@tonic-gate 
16177c478bd9Sstevel@tonic-gate 	    while (init.hasMoreElements()) {
16187c478bd9Sstevel@tonic-gate 		Object test = init.nextElement();
16197c478bd9Sstevel@tonic-gate 		val = test; // for exception..
16207c478bd9Sstevel@tonic-gate 
16217c478bd9Sstevel@tonic-gate 		if (attDescType.equals(JAVA_STRING_TYPE)) {
16227c478bd9Sstevel@tonic-gate 		    test = ((String)test).toLowerCase();
16237c478bd9Sstevel@tonic-gate 
16247c478bd9Sstevel@tonic-gate 		} else if (attDescType.equals(JAVA_OPAQUE_TYPE)) {
16257c478bd9Sstevel@tonic-gate 		    test = new Opaque((byte[])test);
16267c478bd9Sstevel@tonic-gate 
16277c478bd9Sstevel@tonic-gate 		}
16287c478bd9Sstevel@tonic-gate 
16297c478bd9Sstevel@tonic-gate 		if (allowed.indexOf(test) != -1) {
16307c478bd9Sstevel@tonic-gate 		    return; // found it!
16317c478bd9Sstevel@tonic-gate 		}
16327c478bd9Sstevel@tonic-gate 	    }
16337c478bd9Sstevel@tonic-gate 	    // Initializer wasn't found.
16347c478bd9Sstevel@tonic-gate 
16357c478bd9Sstevel@tonic-gate 	    throw
16367c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
1637*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
16387c478bd9Sstevel@tonic-gate 				"template_wrong_init",
16397c478bd9Sstevel@tonic-gate 				new Object[] {
16407c478bd9Sstevel@tonic-gate 		    val.toString(), attDesc.getId()});
16417c478bd9Sstevel@tonic-gate 	}
16427c478bd9Sstevel@tonic-gate     }
16437c478bd9Sstevel@tonic-gate 
16447c478bd9Sstevel@tonic-gate     // Parse the attribute's id string.
16457c478bd9Sstevel@tonic-gate 
parseId(StreamTokenizer tk, AttributeDescriptor attDesc, int baseLineno)16467c478bd9Sstevel@tonic-gate     private void parseId(StreamTokenizer tk,
16477c478bd9Sstevel@tonic-gate 			 AttributeDescriptor attDesc,
16487c478bd9Sstevel@tonic-gate 			 int baseLineno)
16497c478bd9Sstevel@tonic-gate 	throws ServiceLocationException, IOException {
16507c478bd9Sstevel@tonic-gate 
16517c478bd9Sstevel@tonic-gate 	// Parse the attribute's identifier tag.
16527c478bd9Sstevel@tonic-gate 
16537c478bd9Sstevel@tonic-gate 	String id = parseWord(tk, baseLineno);
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate 	int tt = tk.nextToken();
16567c478bd9Sstevel@tonic-gate 
16577c478bd9Sstevel@tonic-gate 	// Parse the seperator.
16587c478bd9Sstevel@tonic-gate 
16597c478bd9Sstevel@tonic-gate 	if (tt != TT_EQUALS) {
16607c478bd9Sstevel@tonic-gate 	    throw
16617c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
1662*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
16637c478bd9Sstevel@tonic-gate 				"template_attr_syntax",
16647c478bd9Sstevel@tonic-gate 				new Object[] {
16657c478bd9Sstevel@tonic-gate 		    Integer.toString(tk.lineno() + baseLineno)});
16667c478bd9Sstevel@tonic-gate 
16677c478bd9Sstevel@tonic-gate 	}
16687c478bd9Sstevel@tonic-gate 
16697c478bd9Sstevel@tonic-gate 	// Expand out any escaped ``#''. It won't be handled by
16707c478bd9Sstevel@tonic-gate 	// SLA.
16717c478bd9Sstevel@tonic-gate 
16727c478bd9Sstevel@tonic-gate 	id = unescapeHash(id);
16737c478bd9Sstevel@tonic-gate 
16747c478bd9Sstevel@tonic-gate 	// Expand out character escapes.
16757c478bd9Sstevel@tonic-gate 
1676*55fea89dSDan Cross 	id =
16777c478bd9Sstevel@tonic-gate 	    ServiceLocationAttribute.unescapeAttributeString(id, true);
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate 
16807c478bd9Sstevel@tonic-gate 	attDesc.setId(id);
16817c478bd9Sstevel@tonic-gate     }
16827c478bd9Sstevel@tonic-gate 
16837c478bd9Sstevel@tonic-gate     // Parse the attribute's type and flags.
16847c478bd9Sstevel@tonic-gate 
1685*55fea89dSDan Cross     private void
parseTypeAndFlags(StreamTokenizer tk, AttributeDescriptor attDesc, int baseLineno)16867c478bd9Sstevel@tonic-gate 	parseTypeAndFlags(StreamTokenizer tk,
16877c478bd9Sstevel@tonic-gate 			  AttributeDescriptor attDesc,
16887c478bd9Sstevel@tonic-gate 			  int baseLineno)
16897c478bd9Sstevel@tonic-gate 	throws ServiceLocationException, IOException {
16907c478bd9Sstevel@tonic-gate 
16917c478bd9Sstevel@tonic-gate 	int existingFlags = 0;
16927c478bd9Sstevel@tonic-gate 
16937c478bd9Sstevel@tonic-gate 	// Parse the attribute's type.
16947c478bd9Sstevel@tonic-gate 
16957c478bd9Sstevel@tonic-gate 	String type = parseWord(tk, baseLineno);
16967c478bd9Sstevel@tonic-gate 
16977c478bd9Sstevel@tonic-gate 	checkAndAddType(type, attDesc, tk.lineno() + baseLineno);
16987c478bd9Sstevel@tonic-gate 
16997c478bd9Sstevel@tonic-gate 	// Parse the flags.
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate 	do {
17027c478bd9Sstevel@tonic-gate 
17037c478bd9Sstevel@tonic-gate 	    // Check if any flags are left.
17047c478bd9Sstevel@tonic-gate 
17057c478bd9Sstevel@tonic-gate 	    if (tk.nextToken() == StreamTokenizer.TT_EOF) {
17067c478bd9Sstevel@tonic-gate 		break;
17077c478bd9Sstevel@tonic-gate 
17087c478bd9Sstevel@tonic-gate 	    } else {
17097c478bd9Sstevel@tonic-gate 		tk.pushBack();
17107c478bd9Sstevel@tonic-gate 	    }
17117c478bd9Sstevel@tonic-gate 
17127c478bd9Sstevel@tonic-gate 	    int lineno = tk.lineno();
17137c478bd9Sstevel@tonic-gate 
17147c478bd9Sstevel@tonic-gate 	    // Parse the flag.
17157c478bd9Sstevel@tonic-gate 
17167c478bd9Sstevel@tonic-gate 	    String flag = parseWord(tk, baseLineno);
17177c478bd9Sstevel@tonic-gate 
17187c478bd9Sstevel@tonic-gate 	    // Error if flags with keyword.
17197c478bd9Sstevel@tonic-gate 
17207c478bd9Sstevel@tonic-gate 	    if (attDesc.getIsKeyword()) {
17217c478bd9Sstevel@tonic-gate 		throw
17227c478bd9Sstevel@tonic-gate 		    new ServiceLocationException(
1723*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
17247c478bd9Sstevel@tonic-gate 				"template_attr_syntax",
17257c478bd9Sstevel@tonic-gate 				new Object[] {
17267c478bd9Sstevel@tonic-gate 			Integer.toString(tk.lineno() + baseLineno)});
17277c478bd9Sstevel@tonic-gate 	    }
17287c478bd9Sstevel@tonic-gate 
17297c478bd9Sstevel@tonic-gate 
17307c478bd9Sstevel@tonic-gate 	    // Check and assign it to the attribute.
1731*55fea89dSDan Cross 
1732*55fea89dSDan Cross 	    existingFlags =
17337c478bd9Sstevel@tonic-gate 		existingFlags | checkAndAddFlag(flag,
17347c478bd9Sstevel@tonic-gate 						existingFlags,
17357c478bd9Sstevel@tonic-gate 						attDesc,
17367c478bd9Sstevel@tonic-gate 						baseLineno + lineno);
17377c478bd9Sstevel@tonic-gate 
17387c478bd9Sstevel@tonic-gate 	} while (true);
17397c478bd9Sstevel@tonic-gate     }
17407c478bd9Sstevel@tonic-gate 
17417c478bd9Sstevel@tonic-gate     // Parse the attribute's initial value(s).
17427c478bd9Sstevel@tonic-gate 
parseDefaultValues(StreamTokenizer tk, AttributeDescriptor attDesc, int baseLineno)17437c478bd9Sstevel@tonic-gate     private void parseDefaultValues(StreamTokenizer tk,
17447c478bd9Sstevel@tonic-gate 				    AttributeDescriptor attDesc,
17457c478bd9Sstevel@tonic-gate 				    int baseLineno)
17467c478bd9Sstevel@tonic-gate 	throws ServiceLocationException, IOException {
17477c478bd9Sstevel@tonic-gate 
17487c478bd9Sstevel@tonic-gate 	// First get the vector of initial values.
17497c478bd9Sstevel@tonic-gate 
17507c478bd9Sstevel@tonic-gate 	Vector vals = parseValueList(tk, attDesc, baseLineno);
17517c478bd9Sstevel@tonic-gate 
17527c478bd9Sstevel@tonic-gate 	// Check whether it works for this attribute. Type
17537c478bd9Sstevel@tonic-gate 	//  checking will be done by value list parsing.
17547c478bd9Sstevel@tonic-gate 
17557c478bd9Sstevel@tonic-gate 	if (!attDesc.getIsMultivalued() && vals.size() > 1) {
17567c478bd9Sstevel@tonic-gate 	    throw
17577c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
1758*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
17597c478bd9Sstevel@tonic-gate 				"template_attr_syntax",
17607c478bd9Sstevel@tonic-gate 				new Object[] {
17617c478bd9Sstevel@tonic-gate 		    Integer.toString(tk.lineno() + baseLineno)});
17627c478bd9Sstevel@tonic-gate 	}
17637c478bd9Sstevel@tonic-gate 
17647c478bd9Sstevel@tonic-gate 	attDesc.setDefaultValues(vals);
17657c478bd9Sstevel@tonic-gate     }
17667c478bd9Sstevel@tonic-gate 
17677c478bd9Sstevel@tonic-gate     // Parse the attribute's allowed values.
17687c478bd9Sstevel@tonic-gate 
1769*55fea89dSDan Cross     private void
parseAllowedValues(StreamTokenizer tk, AttributeDescriptor attDesc, int baseLineno)17707c478bd9Sstevel@tonic-gate 	parseAllowedValues(StreamTokenizer tk,
17717c478bd9Sstevel@tonic-gate 			   AttributeDescriptor attDesc,
17727c478bd9Sstevel@tonic-gate 			   int baseLineno)
17737c478bd9Sstevel@tonic-gate 	throws ServiceLocationException, IOException {
17747c478bd9Sstevel@tonic-gate 
17757c478bd9Sstevel@tonic-gate 	// First get the vector of all allowed values.
17767c478bd9Sstevel@tonic-gate 
17777c478bd9Sstevel@tonic-gate 	Vector vals = parseValueList(tk, attDesc, baseLineno);
17787c478bd9Sstevel@tonic-gate 
17797c478bd9Sstevel@tonic-gate 	// Now set the allowed value vector.
17807c478bd9Sstevel@tonic-gate 
17817c478bd9Sstevel@tonic-gate 	attDesc.setAllowedValues(vals);
17827c478bd9Sstevel@tonic-gate     }
17837c478bd9Sstevel@tonic-gate 
17847c478bd9Sstevel@tonic-gate     // Parse a value list.
17857c478bd9Sstevel@tonic-gate 
parseValueList(StreamTokenizer stk, AttributeDescriptor attDesc, int baseLineno)17867c478bd9Sstevel@tonic-gate     private Vector parseValueList(StreamTokenizer stk,
17877c478bd9Sstevel@tonic-gate 				  AttributeDescriptor attDesc,
17887c478bd9Sstevel@tonic-gate 				  int baseLineno)
17897c478bd9Sstevel@tonic-gate 	throws ServiceLocationException, IOException {
17907c478bd9Sstevel@tonic-gate 
17917c478bd9Sstevel@tonic-gate 	Vector req = new Vector();
17927c478bd9Sstevel@tonic-gate 
17937c478bd9Sstevel@tonic-gate 	// Set up the tokenizer according to the type of the
17947c478bd9Sstevel@tonic-gate 	//  attribute.
17957c478bd9Sstevel@tonic-gate 
17967c478bd9Sstevel@tonic-gate 	String type = attDesc.getValueType();
17977c478bd9Sstevel@tonic-gate 
17987c478bd9Sstevel@tonic-gate 	if (type.equals(JAVA_STRING_TYPE) || type.equals(JAVA_OPAQUE_TYPE)) {
17997c478bd9Sstevel@tonic-gate 	    initStringItemChar(stk);
18007c478bd9Sstevel@tonic-gate 	} else if (type.equals(JAVA_INTEGER_TYPE)) {
18017c478bd9Sstevel@tonic-gate 	    initIntItemChar(stk);
18027c478bd9Sstevel@tonic-gate 	} else if (type.equals(JAVA_BOOLEAN_TYPE)) {
18037c478bd9Sstevel@tonic-gate 	    initIdChar(stk);
18047c478bd9Sstevel@tonic-gate 	}
18057c478bd9Sstevel@tonic-gate 
18067c478bd9Sstevel@tonic-gate 	// Parse through a potentially multivalued value list.
18077c478bd9Sstevel@tonic-gate 
18087c478bd9Sstevel@tonic-gate 	boolean wordRequired = true;	// true when a word is required,
18097c478bd9Sstevel@tonic-gate 					// false when a comma required.
18107c478bd9Sstevel@tonic-gate 	boolean syntaxError = false;
18117c478bd9Sstevel@tonic-gate 	String reqTok = "";
18127c478bd9Sstevel@tonic-gate 	int lineno = 0;
18137c478bd9Sstevel@tonic-gate 
18147c478bd9Sstevel@tonic-gate 	do {
18157c478bd9Sstevel@tonic-gate 	    int tt = stk.nextToken();
18167c478bd9Sstevel@tonic-gate 	    lineno = stk.lineno() + baseLineno;
18177c478bd9Sstevel@tonic-gate 
18187c478bd9Sstevel@tonic-gate 	    if (tt ==  StreamTokenizer.TT_WORD) {
18197c478bd9Sstevel@tonic-gate 
18207c478bd9Sstevel@tonic-gate 		// If a word isn't required, then the case is
18217c478bd9Sstevel@tonic-gate 		//  "token token" and is an error.
18227c478bd9Sstevel@tonic-gate 
18237c478bd9Sstevel@tonic-gate 		if (!wordRequired) {
18247c478bd9Sstevel@tonic-gate 		    syntaxError = true;
18257c478bd9Sstevel@tonic-gate 		}
18267c478bd9Sstevel@tonic-gate 
18277c478bd9Sstevel@tonic-gate 		reqTok = stk.sval.trim();
18287c478bd9Sstevel@tonic-gate 
18297c478bd9Sstevel@tonic-gate 		// Convert the value to the proper object.
18307c478bd9Sstevel@tonic-gate 
18317c478bd9Sstevel@tonic-gate 		Object reqVal = convertValue(type, reqTok, baseLineno);
18327c478bd9Sstevel@tonic-gate 		req.addElement(reqVal);
18337c478bd9Sstevel@tonic-gate 
18347c478bd9Sstevel@tonic-gate 		wordRequired = false;
18357c478bd9Sstevel@tonic-gate 
18367c478bd9Sstevel@tonic-gate 	    } else if (tt == StreamTokenizer.TT_EOF) {
18377c478bd9Sstevel@tonic-gate 
18387c478bd9Sstevel@tonic-gate 		// If a word is required, then list ends with
18397c478bd9Sstevel@tonic-gate 		//  a comma, so error.
18407c478bd9Sstevel@tonic-gate 
18417c478bd9Sstevel@tonic-gate 		if (wordRequired) {
18427c478bd9Sstevel@tonic-gate 		    syntaxError = true;
18437c478bd9Sstevel@tonic-gate 		}
18447c478bd9Sstevel@tonic-gate 
18457c478bd9Sstevel@tonic-gate 		break;
18467c478bd9Sstevel@tonic-gate 
18477c478bd9Sstevel@tonic-gate 	    } else if (tt == TT_COMMA) {
18487c478bd9Sstevel@tonic-gate 
18497c478bd9Sstevel@tonic-gate 		// If a word is required, then error. The case is ",,".
18507c478bd9Sstevel@tonic-gate 
18517c478bd9Sstevel@tonic-gate 		if (wordRequired) {
18527c478bd9Sstevel@tonic-gate 		    syntaxError = true;
18537c478bd9Sstevel@tonic-gate 		    break;
18547c478bd9Sstevel@tonic-gate 		}
18557c478bd9Sstevel@tonic-gate 
18567c478bd9Sstevel@tonic-gate 		// Otherwise, the next token must be a word.
18577c478bd9Sstevel@tonic-gate 
18587c478bd9Sstevel@tonic-gate 		wordRequired = true;
18597c478bd9Sstevel@tonic-gate 
18607c478bd9Sstevel@tonic-gate 	    } else {
18617c478bd9Sstevel@tonic-gate 
18627c478bd9Sstevel@tonic-gate 		// No other tokens are allowed.
18637c478bd9Sstevel@tonic-gate 
18647c478bd9Sstevel@tonic-gate 		syntaxError = true;
18657c478bd9Sstevel@tonic-gate 		break;
18667c478bd9Sstevel@tonic-gate 	    }
18677c478bd9Sstevel@tonic-gate 
18687c478bd9Sstevel@tonic-gate 	} while (true);
18697c478bd9Sstevel@tonic-gate 
18707c478bd9Sstevel@tonic-gate 	if (syntaxError) {
18717c478bd9Sstevel@tonic-gate 
18727c478bd9Sstevel@tonic-gate 	    throw
18737c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
1874*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
18757c478bd9Sstevel@tonic-gate 				"template_attr_syntax",
18767c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(lineno)});
18777c478bd9Sstevel@tonic-gate 	}
18787c478bd9Sstevel@tonic-gate 
18797c478bd9Sstevel@tonic-gate 	return req;
18807c478bd9Sstevel@tonic-gate 
18817c478bd9Sstevel@tonic-gate     }
18827c478bd9Sstevel@tonic-gate 
18837c478bd9Sstevel@tonic-gate     // Check the type and add it to the attribute descriptor.
18847c478bd9Sstevel@tonic-gate 
checkAndAddType(String type, AttributeDescriptor attDesc, int lineno)18857c478bd9Sstevel@tonic-gate     private void checkAndAddType(String type,
18867c478bd9Sstevel@tonic-gate 				 AttributeDescriptor attDesc,
1887*55fea89dSDan Cross 				 int lineno)
18887c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
18897c478bd9Sstevel@tonic-gate 
18907c478bd9Sstevel@tonic-gate 	// Check token against recognized types.
18917c478bd9Sstevel@tonic-gate 
18927c478bd9Sstevel@tonic-gate 	if (type.equalsIgnoreCase(STRING_TYPE)) {
18937c478bd9Sstevel@tonic-gate 	    attDesc.setValueType(JAVA_STRING_TYPE);
18947c478bd9Sstevel@tonic-gate 
18957c478bd9Sstevel@tonic-gate 	} else if (type.equalsIgnoreCase(INTEGER_TYPE)) {
18967c478bd9Sstevel@tonic-gate 	    attDesc.setValueType(JAVA_INTEGER_TYPE);
18977c478bd9Sstevel@tonic-gate 
18987c478bd9Sstevel@tonic-gate 	} else if (type.equalsIgnoreCase(BOOLEAN_TYPE)) {
18997c478bd9Sstevel@tonic-gate 	    attDesc.setValueType(JAVA_BOOLEAN_TYPE);
19007c478bd9Sstevel@tonic-gate 
19017c478bd9Sstevel@tonic-gate 	} else if (type.equalsIgnoreCase(OPAQUE_TYPE)) {
19027c478bd9Sstevel@tonic-gate 	    attDesc.setValueType(JAVA_OPAQUE_TYPE);
19037c478bd9Sstevel@tonic-gate 
19047c478bd9Sstevel@tonic-gate 	} else if (type.equalsIgnoreCase(KEYWORD_TYPE)) {
19057c478bd9Sstevel@tonic-gate 	    attDesc.setIsKeyword(true);
19067c478bd9Sstevel@tonic-gate 
19077c478bd9Sstevel@tonic-gate 	} else {
19087c478bd9Sstevel@tonic-gate 
19097c478bd9Sstevel@tonic-gate 	    throw
19107c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
1911*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
19127c478bd9Sstevel@tonic-gate 				"template_not_slp_type",
19137c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(lineno)});
19147c478bd9Sstevel@tonic-gate 	}
19157c478bd9Sstevel@tonic-gate 
19167c478bd9Sstevel@tonic-gate     }
1917*55fea89dSDan Cross 
19187c478bd9Sstevel@tonic-gate     // Check the flag and add it to the attribute descriptor.
19197c478bd9Sstevel@tonic-gate 
checkAndAddFlag(String flag, int matched, AttributeDescriptor attDesc, int lineno)19207c478bd9Sstevel@tonic-gate     private int checkAndAddFlag(String flag,
19217c478bd9Sstevel@tonic-gate 				int matched,
19227c478bd9Sstevel@tonic-gate 				AttributeDescriptor attDesc,
1923*55fea89dSDan Cross 				int lineno)
19247c478bd9Sstevel@tonic-gate 	throws ServiceLocationException {
19257c478bd9Sstevel@tonic-gate 
19267c478bd9Sstevel@tonic-gate 	boolean duplicate = false;
19277c478bd9Sstevel@tonic-gate 
19287c478bd9Sstevel@tonic-gate 	// We depend on the attribute descriptor being initialized to
19297c478bd9Sstevel@tonic-gate 	// nothing, i.e. false for all flags and for keyword.
19307c478bd9Sstevel@tonic-gate 
19317c478bd9Sstevel@tonic-gate 	if (flag.equalsIgnoreCase(MULTIPLE_FLAG)) {
19327c478bd9Sstevel@tonic-gate 
19337c478bd9Sstevel@tonic-gate 	    if ((matched & MULTIPLE_MASK) != 0) {
19347c478bd9Sstevel@tonic-gate 		duplicate = true;
19357c478bd9Sstevel@tonic-gate 
19367c478bd9Sstevel@tonic-gate 	    } else {
19377c478bd9Sstevel@tonic-gate 
19387c478bd9Sstevel@tonic-gate 		// Check for boolean. Booleans may not have
19397c478bd9Sstevel@tonic-gate 		// multiple values.
19407c478bd9Sstevel@tonic-gate 
19417c478bd9Sstevel@tonic-gate 		if (attDesc.getValueType().equals(JAVA_BOOLEAN_TYPE)) {
19427c478bd9Sstevel@tonic-gate 
19437c478bd9Sstevel@tonic-gate 		    throw
19447c478bd9Sstevel@tonic-gate 			new ServiceLocationException(
1945*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
19467c478bd9Sstevel@tonic-gate 				"template_boolean_multi",
19477c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(lineno)});
19487c478bd9Sstevel@tonic-gate 		}
19497c478bd9Sstevel@tonic-gate 
19507c478bd9Sstevel@tonic-gate 		attDesc.setIsMultivalued(true);
19517c478bd9Sstevel@tonic-gate 		return MULTIPLE_MASK;
19527c478bd9Sstevel@tonic-gate 
19537c478bd9Sstevel@tonic-gate 	    }
19547c478bd9Sstevel@tonic-gate 
19557c478bd9Sstevel@tonic-gate 	} else if (flag.equalsIgnoreCase(LITERAL_FLAG)) {
19567c478bd9Sstevel@tonic-gate 
19577c478bd9Sstevel@tonic-gate 	    if ((matched & LITERAL_MASK) != 0) {
19587c478bd9Sstevel@tonic-gate 		duplicate = true;
19597c478bd9Sstevel@tonic-gate 
19607c478bd9Sstevel@tonic-gate 	    } else {
19617c478bd9Sstevel@tonic-gate 		attDesc.setIsLiteral(true);
19627c478bd9Sstevel@tonic-gate 		return LITERAL_MASK;
19637c478bd9Sstevel@tonic-gate 	    }
19647c478bd9Sstevel@tonic-gate 
19657c478bd9Sstevel@tonic-gate 	} else if (flag.equalsIgnoreCase(EXPLICIT_FLAG)) {
19667c478bd9Sstevel@tonic-gate 
19677c478bd9Sstevel@tonic-gate 	    if ((matched & EXPLICIT_MASK) != 0) {
19687c478bd9Sstevel@tonic-gate 		duplicate = true;
19697c478bd9Sstevel@tonic-gate 
19707c478bd9Sstevel@tonic-gate 	    } else {
19717c478bd9Sstevel@tonic-gate 		attDesc.setRequiresExplicitMatch(true);
19727c478bd9Sstevel@tonic-gate 		return EXPLICIT_MASK;
19737c478bd9Sstevel@tonic-gate 	    }
19747c478bd9Sstevel@tonic-gate 
19757c478bd9Sstevel@tonic-gate 	} else if (flag.equalsIgnoreCase(OPTIONAL_FLAG)) {
19767c478bd9Sstevel@tonic-gate 
19777c478bd9Sstevel@tonic-gate 	    if ((matched & OPTIONAL_MASK) != 0) {
19787c478bd9Sstevel@tonic-gate 		duplicate = true;
19797c478bd9Sstevel@tonic-gate 
19807c478bd9Sstevel@tonic-gate 	    } else {
19817c478bd9Sstevel@tonic-gate 		attDesc.setIsOptional(true);
19827c478bd9Sstevel@tonic-gate 		return OPTIONAL_MASK;
19837c478bd9Sstevel@tonic-gate 	    }
19847c478bd9Sstevel@tonic-gate 
19857c478bd9Sstevel@tonic-gate 	} else {
19867c478bd9Sstevel@tonic-gate 
19877c478bd9Sstevel@tonic-gate 	    throw
19887c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
1989*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
19907c478bd9Sstevel@tonic-gate 				"template_invalid_attr_flag",
19917c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(lineno)});
19927c478bd9Sstevel@tonic-gate 	}
19937c478bd9Sstevel@tonic-gate 
19947c478bd9Sstevel@tonic-gate 
19957c478bd9Sstevel@tonic-gate 	if (duplicate) {
19967c478bd9Sstevel@tonic-gate 	    throw
19977c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
1998*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
19997c478bd9Sstevel@tonic-gate 				"template_dup_attr_flag",
20007c478bd9Sstevel@tonic-gate 				new Object[] {Integer.toString(lineno)});
20017c478bd9Sstevel@tonic-gate 	}
20027c478bd9Sstevel@tonic-gate 
20037c478bd9Sstevel@tonic-gate 	return 0; // never happens.
20047c478bd9Sstevel@tonic-gate     }
20057c478bd9Sstevel@tonic-gate 
20067c478bd9Sstevel@tonic-gate     // Parse a word out of the tokenizer. The exact characters
20077c478bd9Sstevel@tonic-gate     //  will depend on what the syntax tables have been set to.
20087c478bd9Sstevel@tonic-gate 
parseWord(StreamTokenizer tk, int baseLineno)2009*55fea89dSDan Cross     private String parseWord(StreamTokenizer tk, int baseLineno)
20107c478bd9Sstevel@tonic-gate 	throws ServiceLocationException, IOException {
20117c478bd9Sstevel@tonic-gate 
20127c478bd9Sstevel@tonic-gate 	int tt = tk.nextToken();
20137c478bd9Sstevel@tonic-gate 
20147c478bd9Sstevel@tonic-gate 	if (tt == StreamTokenizer.TT_WORD) {
20157c478bd9Sstevel@tonic-gate 	    return (tk.sval);
20167c478bd9Sstevel@tonic-gate 
20177c478bd9Sstevel@tonic-gate 	} else {
20187c478bd9Sstevel@tonic-gate 
20197c478bd9Sstevel@tonic-gate 	    String errorToken = "";
20207c478bd9Sstevel@tonic-gate 
20217c478bd9Sstevel@tonic-gate 	    // Report the erroneous characters.
20227c478bd9Sstevel@tonic-gate 
20237c478bd9Sstevel@tonic-gate 	    if (tt == StreamTokenizer.TT_NUMBER) {
20247c478bd9Sstevel@tonic-gate 		errorToken = Double.toString(tk.nval);
20257c478bd9Sstevel@tonic-gate 	    } else if (tt == StreamTokenizer.TT_EOL) {
20267c478bd9Sstevel@tonic-gate 		errorToken = "<end of line>";
20277c478bd9Sstevel@tonic-gate 	    } else if (tt == StreamTokenizer.TT_EOF) {
20287c478bd9Sstevel@tonic-gate 		errorToken = "<end of file>";
20297c478bd9Sstevel@tonic-gate 	    } else {
20307c478bd9Sstevel@tonic-gate 		errorToken = (new Character((char)tt)).toString();
20317c478bd9Sstevel@tonic-gate 	    }
2032*55fea89dSDan Cross 
20337c478bd9Sstevel@tonic-gate 	    throw
20347c478bd9Sstevel@tonic-gate 		new ServiceLocationException(
2035*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
20367c478bd9Sstevel@tonic-gate 				"template_invalid_tok",
20377c478bd9Sstevel@tonic-gate 				new Object[] {
20387c478bd9Sstevel@tonic-gate 		    Integer.toString(tk.lineno() + baseLineno)});
20397c478bd9Sstevel@tonic-gate 
20407c478bd9Sstevel@tonic-gate 	}
20417c478bd9Sstevel@tonic-gate 
20427c478bd9Sstevel@tonic-gate     }
20437c478bd9Sstevel@tonic-gate 
20447c478bd9Sstevel@tonic-gate     // Convert a value list token to the value.
20457c478bd9Sstevel@tonic-gate 
convertValue(String type, String reqTok, int lineno)20467c478bd9Sstevel@tonic-gate     private Object convertValue(String type,
20477c478bd9Sstevel@tonic-gate 				String reqTok,
2048*55fea89dSDan Cross 				int lineno)
20497c478bd9Sstevel@tonic-gate 	throws ServiceLocationException,
20507c478bd9Sstevel@tonic-gate 	       IOException {
20517c478bd9Sstevel@tonic-gate 
20527c478bd9Sstevel@tonic-gate 	Object reqVal = null;
20537c478bd9Sstevel@tonic-gate 
20547c478bd9Sstevel@tonic-gate 	if (type.equals(JAVA_STRING_TYPE)) {
2055*55fea89dSDan Cross 
20567c478bd9Sstevel@tonic-gate 	    // Expand out any escaped ``#''. It won't be handled by
20577c478bd9Sstevel@tonic-gate 	    //  SLA.
20587c478bd9Sstevel@tonic-gate 
20597c478bd9Sstevel@tonic-gate 	    reqTok = unescapeHash(reqTok);
20607c478bd9Sstevel@tonic-gate 
20617c478bd9Sstevel@tonic-gate 	    // Expand out character escapes.
20627c478bd9Sstevel@tonic-gate 
2063*55fea89dSDan Cross 	    reqVal =
20647c478bd9Sstevel@tonic-gate 		ServiceLocationAttribute.unescapeAttributeString(reqTok,
20657c478bd9Sstevel@tonic-gate 								 false);
20667c478bd9Sstevel@tonic-gate 
20677c478bd9Sstevel@tonic-gate 	} else if (type.equals(JAVA_INTEGER_TYPE)) {
20687c478bd9Sstevel@tonic-gate 
20697c478bd9Sstevel@tonic-gate 	    try {
20707c478bd9Sstevel@tonic-gate 
20717c478bd9Sstevel@tonic-gate 		reqVal = Integer.valueOf(reqTok);
20727c478bd9Sstevel@tonic-gate 
20737c478bd9Sstevel@tonic-gate 	    } catch (NumberFormatException ex) {
20747c478bd9Sstevel@tonic-gate 
2075*55fea89dSDan Cross 		throw
20767c478bd9Sstevel@tonic-gate 		    new ServiceLocationException(
2077*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
20787c478bd9Sstevel@tonic-gate 				"template_expect_int",
20797c478bd9Sstevel@tonic-gate 				new Object[] {
20807c478bd9Sstevel@tonic-gate 			Integer.toString(lineno), reqTok });
20817c478bd9Sstevel@tonic-gate 	    }
20827c478bd9Sstevel@tonic-gate 	} else if (type.equals(JAVA_BOOLEAN_TYPE)) {
20837c478bd9Sstevel@tonic-gate 
20847c478bd9Sstevel@tonic-gate 	    // Boolean.valueOf() doesn't handle this properly.
20857c478bd9Sstevel@tonic-gate 
20867c478bd9Sstevel@tonic-gate 	    if (reqTok.equalsIgnoreCase(TRUE_TOKEN)) {
20877c478bd9Sstevel@tonic-gate 
20887c478bd9Sstevel@tonic-gate 		reqVal = new Boolean(true);
20897c478bd9Sstevel@tonic-gate 
20907c478bd9Sstevel@tonic-gate 	    } else if (reqTok.equalsIgnoreCase(FALSE_TOKEN)) {
2091*55fea89dSDan Cross 
20927c478bd9Sstevel@tonic-gate 		reqVal = new Boolean(false);
20937c478bd9Sstevel@tonic-gate 
20947c478bd9Sstevel@tonic-gate 	    } else {
20957c478bd9Sstevel@tonic-gate 
20967c478bd9Sstevel@tonic-gate 		throw
20977c478bd9Sstevel@tonic-gate 		    new ServiceLocationException(
2098*55fea89dSDan Cross 				ServiceLocationException.PARSE_ERROR,
20997c478bd9Sstevel@tonic-gate 				"template_expect_bool",
21007c478bd9Sstevel@tonic-gate 				new Object[] {
21017c478bd9Sstevel@tonic-gate 			Integer.toString(lineno), reqTok});
21027c478bd9Sstevel@tonic-gate 	    }
21037c478bd9Sstevel@tonic-gate 	} else if (type.equals(JAVA_OPAQUE_TYPE)) {
2104*55fea89dSDan Cross 
21057c478bd9Sstevel@tonic-gate 	    reqVal = Opaque.unescapeByteArray(reqTok);
21067c478bd9Sstevel@tonic-gate 
21077c478bd9Sstevel@tonic-gate 	} else {
21087c478bd9Sstevel@tonic-gate 
21097c478bd9Sstevel@tonic-gate 	    Assert.slpassert(false,
21107c478bd9Sstevel@tonic-gate 			  "template_attr_desc",
21117c478bd9Sstevel@tonic-gate 			  new Object[0]);
21127c478bd9Sstevel@tonic-gate 	}
21137c478bd9Sstevel@tonic-gate 
21147c478bd9Sstevel@tonic-gate 	return reqVal;
21157c478bd9Sstevel@tonic-gate     }
21167c478bd9Sstevel@tonic-gate 
21177c478bd9Sstevel@tonic-gate     // Expand out any escaped hashes. Not handled by SLA.
21187c478bd9Sstevel@tonic-gate 
unescapeHash(String str)21197c478bd9Sstevel@tonic-gate     private String unescapeHash(String str) {
21207c478bd9Sstevel@tonic-gate 
21217c478bd9Sstevel@tonic-gate 	StringBuffer buf = new StringBuffer();
21227c478bd9Sstevel@tonic-gate 	int len = ESC_HASH.length();
21237c478bd9Sstevel@tonic-gate 	int i, j = 0;
21247c478bd9Sstevel@tonic-gate 
21257c478bd9Sstevel@tonic-gate 	for (i = str.indexOf(ESC_HASH, j);
2126*55fea89dSDan Cross 	    i != -1;
21277c478bd9Sstevel@tonic-gate 	    i = str.indexOf(ESC_HASH, j)) {
21287c478bd9Sstevel@tonic-gate 
21297c478bd9Sstevel@tonic-gate 	    buf.append(str.substring(j, i));
21307c478bd9Sstevel@tonic-gate 	    buf.append(HASH);
21317c478bd9Sstevel@tonic-gate 	    j = i + len;
21327c478bd9Sstevel@tonic-gate 	}
21337c478bd9Sstevel@tonic-gate 
21347c478bd9Sstevel@tonic-gate 	len = str.length();
21357c478bd9Sstevel@tonic-gate 
21367c478bd9Sstevel@tonic-gate 	if (j < len) {
21377c478bd9Sstevel@tonic-gate 	    buf.append(str.substring(j, len));
21387c478bd9Sstevel@tonic-gate 
21397c478bd9Sstevel@tonic-gate 	}
21407c478bd9Sstevel@tonic-gate 
21417c478bd9Sstevel@tonic-gate 	return buf.toString();
21427c478bd9Sstevel@tonic-gate     }
21437c478bd9Sstevel@tonic-gate 
21447c478bd9Sstevel@tonic-gate }
2145