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