2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A// AttributeVerifier.java: An attribute verifier for SLP attributes.
2N/A// Author: James Kempf
2N/A// Created On: Thu Jun 19 10:51:32 1997
2N/A// Last Modified By: James Kempf
2N/A// Last Modified On: Mon Nov 9 10:21:02 1998
2N/A// Update Count: 200
2N/A//
2N/A
2N/Apackage com.sun.slp;
2N/A
2N/Aimport java.util.*;
2N/Aimport java.io.*;
2N/A
2N/A/**
2N/A * The AttributeVerifier class implements the ServiceLocationAttributeVerifier
2N/A * interface, but without committment to a particular mechanism for
2N/A * obtaining the template defintion. Subclasses provide the mechanism,
2N/A * and pass in the template to the parent as a Reader during object
2N/A * creation. The AttributeVerifier class parses tokens from the Reader and
2N/A * constructs the attribute descriptor objects describing the attribute. These
2N/A * are used during verification of the attribute. The AttributeVerifier
2N/A * and implementations of the attribute descriptors are free to optimize
2N/A * space utilization by lazily evaluating portions of the attribute
2N/A * template.
2N/A *
2N/A * @author James Kempf
2N/A *
2N/A */
2N/A
2N/Aclass AttributeVerifier
2N/A extends Object
2N/A implements ServiceLocationAttributeVerifier {
2N/A
2N/A // Template specific escape.
2N/A
2N/A private static final String ESC_HASH = "\\23";
2N/A private static final String HASH = "#";
2N/A
2N/A // Number of template attributes.
2N/A
2N/A private static final int TEMPLATE_ATTR_NO = 5;
2N/A
2N/A // Bitfields for found template attributes.
2N/A
2N/A private static final int SERVICE_MASK = 0x01;
2N/A private static final int VERSION_MASK = 0x02;
2N/A private static final int DESCRIPTION_MASK = 0x08;
2N/A private static final int URL_PATH_RULES_MASK = 0x10;
2N/A
2N/A // When all template attribute assignments are found.
2N/A
2N/A private static final int TEMPLATE_FOUND = (SERVICE_MASK |
2N/A VERSION_MASK |
2N/A DESCRIPTION_MASK |
2N/A URL_PATH_RULES_MASK);
2N/A
2N/A // These are the valid SLP types.
2N/A
2N/A private static final String INTEGER_TYPE = "integer";
2N/A private static final String STRING_TYPE = "string";
2N/A private static final String BOOLEAN_TYPE = "boolean";
2N/A private static final String OPAQUE_TYPE = "opaque";
2N/A private static final String KEYWORD_TYPE = "keyword";
2N/A
2N/A // These are the corresponding Java types. Package public so
2N/A // others (SLPConfig for example) can get at them.
2N/A
2N/A static final String JAVA_STRING_TYPE =
2N/A "java.lang.String";
2N/A static final String JAVA_INTEGER_TYPE =
2N/A "java.lang.Integer";
2N/A static final String JAVA_BOOLEAN_TYPE =
2N/A "java.lang.Boolean";
2N/A static final String JAVA_OPAQUE_TYPE =
2N/A "[B";
2N/A
2N/A // Tokens for boolean values.
2N/A
2N/A private static final String TRUE_TOKEN = "true";
2N/A private static final String FALSE_TOKEN = "false";
2N/A
2N/A // This is the number of flags.
2N/A
2N/A private static final int FLAG_NO = 4;
2N/A
2N/A // These are the flags.
2N/A
2N/A private static final String MULTIPLE_FLAG = "m";
2N/A private static final String LITERAL_FLAG = "l";
2N/A private static final String EXPLICIT_FLAG = "x";
2N/A private static final String OPTIONAL_FLAG = "o";
2N/A
2N/A // These masks help determine whether the flags have been duplicated.
2N/A
2N/A private static final byte MULTIPLE_MASK = 0x01;
2N/A private static final byte LITERAL_MASK = 0x02;
2N/A private static final byte EXPLICIT_MASK = 0x04;
2N/A private static final byte OPTIONAL_MASK = 0x08;
2N/A
2N/A // These are tokens for separator characters.
2N/A
2N/A private static final char TT_COMMA = ',';
2N/A private static final char TT_EQUALS = '=';
2N/A private static final char TT_FIELD = '#';
2N/A private static final char TT_ESCAPE = '\\';
2N/A
2N/A // This token is for checking version number
2N/A // attribute assignment.
2N/A
2N/A private static final char TT_PERIOD = '.';
2N/A
2N/A // Radix64 code characters.
2N/A
2N/A private static final char UPPER_START_CODE = 'A';
2N/A private static final char UPPER_END_CODE = 'Z';
2N/A private static final char LOWER_START_CODE = 'a';
2N/A private static final char LOWER_END_CODE = 'z';
2N/A private static final char NUMBER_START_CODE = '0';
2N/A private static final char NUMBER_END_CODE = '9';
2N/A private static final char EXTRA_CODE1 = '+';
2N/A private static final char EXTRA_CODE2 = '/';
2N/A private static final char PAD_CODE = '=';
2N/A private static final char LENGTH_SEPERATOR = ':';
2N/A
2N/A // The SLP service type of this template.
2N/A
2N/A private ServiceType serviceType;
2N/A
2N/A // The template's language locale.
2N/A
2N/A private Locale locale;
2N/A
2N/A // The template's version.
2N/A
2N/A private String version;
2N/A
2N/A // The template's URL syntax.
2N/A
2N/A private String URLSyntax;
2N/A
2N/A // The template's description.
2N/A
2N/A private String description;
2N/A
2N/A // The attribute descriptors.
2N/A
2N/A private Hashtable attributeDescriptors = new Hashtable();
2N/A
2N/A //
2N/A // Constructors.
2N/A
2N/A AttributeVerifier() {
2N/A
2N/A }
2N/A
2N/A // Initialize the attribute verifier with a reader. Subclasses or clients
2N/A // pass in a Reader on the template that is used for parsing. This
2N/A // method is used when the template includes the template attributes
2N/A // and URL rules.
2N/A
2N/A void initialize(Reader r) throws ServiceLocationException {
2N/A
2N/A // Use a StreamTokenizer to parse.
2N/A
2N/A StreamTokenizer tk = new StreamTokenizer(r);
2N/A
2N/A // Initialize tokenizer for parsing main.
2N/A
2N/A initFieldChar(tk);
2N/A
2N/A // Now parse the attribute template, including template attributes.
2N/A
2N/A parseTemplate(tk);
2N/A }
2N/A
2N/A // Initialize with this method when no template attributes are involved.
2N/A
2N/A void initializeAttributesOnly(Reader r)
2N/A throws ServiceLocationException {
2N/A
2N/A // Use a StreamTokenizer to parse.
2N/A
2N/A StreamTokenizer tk = new StreamTokenizer(r);
2N/A
2N/A // Initialize tokenizer for parsing main.
2N/A
2N/A initFieldChar(tk);
2N/A
2N/A // Now parse the attribute templates, but no template attributes.
2N/A
2N/A parseAttributes(tk);
2N/A }
2N/A
2N/A //
2N/A // ServiceLocationAttributeVerifier interface implementation.
2N/A //
2N/A
2N/A /**
2N/A * Returns the SLP service type for which this is the verifier.
2N/A *
2N/A * @return The SLP service type name.
2N/A */
2N/A
2N/A public ServiceType getServiceType() {
2N/A
2N/A return serviceType;
2N/A }
2N/A
2N/A /**
2N/A * Returns the SLP language locale of this is the verifier.
2N/A *
2N/A * @return The SLP language locale.
2N/A */
2N/A
2N/A public Locale getLocale() {
2N/A
2N/A return locale;
2N/A }
2N/A
2N/A /**
2N/A * Returns the SLP version of this is the verifier.
2N/A *
2N/A * @return The SLP version.
2N/A */
2N/A
2N/A public String getVersion() {
2N/A
2N/A return version;
2N/A }
2N/A
2N/A /**
2N/A * Returns the SLP URL syntax of this is the verifier.
2N/A *
2N/A * @return The SLP URL syntax.
2N/A */
2N/A
2N/A public String getURLSyntax() {
2N/A
2N/A return URLSyntax;
2N/A }
2N/A
2N/A /**
2N/A * Returns the SLP description of this is the verifier.
2N/A *
2N/A * @return The SLP description.
2N/A */
2N/A
2N/A public String getDescription() {
2N/A
2N/A return description;
2N/A }
2N/A
2N/A /**
2N/A * Returns the ServiceLocationAttributeDescriptor object for the
2N/A * attribute having the named id. IF no such attribute exists in the
2N/A * template, returns null. This method is primarily for GUI tools to
2N/A * display attribute information. Programmatic verification of attributes
2N/A * should use the verifyAttribute() method.
2N/A *
2N/A * @param attrId Id of attribute to return.
2N/A * @return The ServiceLocationAttributeDescriptor object corresponding
2N/A * to the parameter, or null if none.
2N/A */
2N/A
2N/A public ServiceLocationAttributeDescriptor
2N/A getAttributeDescriptor(String attrId) {
2N/A
2N/A return
2N/A (ServiceLocationAttributeDescriptor)
2N/A attributeDescriptors.get(attrId.toLowerCase());
2N/A
2N/A }
2N/A
2N/A /**
2N/A * Returns an Enumeration of
2N/A * ServiceLocationAttributeDescriptors for the template. This method
2N/A * is primarily for GUI tools to display attribute information.
2N/A * Programmatic verification of attributes should use the
2N/A * verifyAttribute() method. Note that small memory implementations
2N/A * may want to implement the Enumeration so that attributes are
2N/A * parsed on demand rather than at creation time.
2N/A *
2N/A * @return A Dictionary with attribute id's as the keys and
2N/A * ServiceLocationAttributeDescriptor objects for the
2N/A * attributes as the values.
2N/A */
2N/A
2N/A public Enumeration getAttributeDescriptors() {
2N/A
2N/A return ((Hashtable)attributeDescriptors.clone()).elements();
2N/A
2N/A }
2N/A
2N/A /**
2N/A * Verify that the attribute parameter is a valid SLP attribute.
2N/A *
2N/A * @param attribute The ServiceLocationAttribute to be verified.
2N/A */
2N/A
2N/A public void verifyAttribute(ServiceLocationAttribute attribute)
2N/A throws ServiceLocationException {
2N/A
2N/A String id = attribute.getId().toLowerCase();
2N/A ServiceLocationAttributeDescriptor des =
2N/A (ServiceLocationAttributeDescriptor)attributeDescriptors.get(id);
2N/A
2N/A if (des == null) {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_no_attribute",
2N/A new Object[] { id });
2N/A }
2N/A
2N/A
2N/A String type = des.getValueType();
2N/A Vector vals = attribute.getValues();
2N/A
2N/A // If keyword, check that no values were specified.
2N/A
2N/A if (des.getIsKeyword()) {
2N/A
2N/A if (vals != null) {
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_not_null",
2N/A new Object[] { id });
2N/A }
2N/A } else {
2N/A
2N/A int i, n;
2N/A
2N/A // Check that a values vector exists, and, if the attribute is
2N/A // not multivalued, only one element is in it.
2N/A
2N/A if (vals == null) {
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_null",
2N/A new Object[] { id });
2N/A
2N/A }
2N/A
2N/A n = vals.size();
2N/A
2N/A if (n > 1 && !des.getIsMultivalued()) {
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_not_multi",
2N/A new Object[] { id });
2N/A }
2N/A
2N/A // Get allowed values.
2N/A
2N/A Vector av = null;
2N/A Enumeration en = des.getAllowedValues();
2N/A
2N/A if (en.hasMoreElements()) {
2N/A av = new Vector();
2N/A
2N/A while (en.hasMoreElements()) {
2N/A Object v = en.nextElement();
2N/A
2N/A // Lower case if string, convert to Opaque if byte array.
2N/A
2N/A if (type.equals(JAVA_STRING_TYPE)) {
2N/A v = ((String)v).toLowerCase();
2N/A
2N/A } else if (type.equals(JAVA_OPAQUE_TYPE)) {
2N/A v = new Opaque((byte[])v);
2N/A
2N/A }
2N/A av.addElement(v);
2N/A
2N/A }
2N/A }
2N/A
2N/A // Check that the types of the values vector match the attribute
2N/A // type. Also, if any allowed values, that attribute values
2N/A // match.
2N/A
2N/A String attTypeName = des.getValueType();
2N/A
2N/A for (i = 0; i < n; i++) {
2N/A Object val = vals.elementAt(i);
2N/A
2N/A String typeName = val.getClass().getName();
2N/A
2N/A if (!typeName.equals(attTypeName)) {
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_type_mismatch",
2N/A new Object[] { id, typeName, attTypeName });
2N/A
2N/A }
2N/A
2N/A // Convert value for comparison, if necessary.
2N/A
2N/A if (type.equals(JAVA_STRING_TYPE)) {
2N/A val = ((String)val).toLowerCase();
2N/A
2N/A } else if (type.equals(JAVA_OPAQUE_TYPE)) {
2N/A val = new Opaque((byte[])val);
2N/A
2N/A }
2N/A
2N/A if (av != null && !av.contains(val)) {
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_not_allowed_value",
2N/A new Object[] {id, val});
2N/A
2N/A }
2N/A }
2N/A
2N/A }
2N/A
2N/A // No way to verify `X' because that's a search property. We
2N/A // must verify `O' in the context of an attribute set.
2N/A }
2N/A
2N/A /**
2N/A * Verify that the set of registration attributes matches the
2N/A * required attributes for the service.
2N/A *
2N/A * @param attributeVector A Vector of ServiceLocationAttribute objects
2N/A * for the registration.
2N/A * @exception ServiceLocationException Thrown if the
2N/A * attribute set is not valid. The message contains information
2N/A * on the attribute name and problem.
2N/A */
2N/A
2N/A public void verifyRegistration(Vector attributeVector)
2N/A throws ServiceLocationException {
2N/A
2N/A Assert.nonNullParameter(attributeVector, "attributeVector");
2N/A
2N/A
2N/A if (attributeVector.size() <= 0) {
2N/A
2N/A // Check whether any attributes are required. If so, then
2N/A // there's an error.
2N/A
2N/A Enumeration en = attributeDescriptors.elements();
2N/A
2N/A while (en.hasMoreElements()) {
2N/A ServiceLocationAttributeDescriptor attDesc =
2N/A (ServiceLocationAttributeDescriptor)en.nextElement();
2N/A
2N/A if (!attDesc.getIsOptional()) {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_missing_required",
2N/A new Object[] { attDesc.getId() });
2N/A }
2N/A }
2N/A } else {
2N/A
2N/A // Construct a hashtable of incoming objects, verifying them
2N/A // while doing so.
2N/A
2N/A int i, n = attributeVector.size();
2N/A Hashtable incoming = new Hashtable();
2N/A
2N/A for (i = 0; i < n; i++) {
2N/A ServiceLocationAttribute attribute =
2N/A (ServiceLocationAttribute)attributeVector.elementAt(i);
2N/A String id = attribute.getId().toLowerCase();
2N/A
2N/A // If we already have it, signal a duplicate.
2N/A
2N/A if (incoming.get(id) != null) {
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_dup",
2N/A new Object[] { attribute.getId() });
2N/A
2N/A }
2N/A
2N/A verifyAttribute(attribute);
2N/A
2N/A incoming.put(id, attribute);
2N/A }
2N/A
2N/A // Now check that all required attributes are present.
2N/A
2N/A Enumeration en = attributeDescriptors.elements();
2N/A
2N/A while (en.hasMoreElements()) {
2N/A ServiceLocationAttributeDescriptor attDesc =
2N/A (ServiceLocationAttributeDescriptor)en.nextElement();
2N/A String attrId = attDesc.getId();
2N/A
2N/A if (!attDesc.getIsOptional() &&
2N/A incoming.get(attrId.toLowerCase()) == null) {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_missing_required",
2N/A new Object[] { attrId });
2N/A }
2N/A }
2N/A }
2N/A
2N/A }
2N/A
2N/A //
2N/A // Private implementation. This is the template attribute parser.
2N/A //
2N/A
2N/A //
2N/A // Tokenizer initializers.
2N/A
2N/A // Base initialization. Resets syntax tables, sets up EOL parsing,
2N/A // and makes word case significant.
2N/A
2N/A private void initForBase(StreamTokenizer tk) {
2N/A
2N/A // Each part of an attribute production must specify which
2N/A // characters belong to words.
2N/A
2N/A tk.resetSyntax();
2N/A
2N/A // Note that we have to make EOL be whitespace even if significant
2N/A // because otherwise the line number won't be correctly incremented.
2N/A
2N/A tk.whitespaceChars((int)'\n', (int)'\n');
2N/A
2N/A // Don't lower case tokens.
2N/A
2N/A tk.lowerCaseMode(false);
2N/A }
2N/A
2N/A // Initialize those token characters that appear in all
2N/A // productions.
2N/A
2N/A private void initCommonToken(StreamTokenizer tk) {
2N/A
2N/A // These characters are recognized as parts of tokens.
2N/A
2N/A tk.wordChars((int)'A', (int)'Z');
2N/A tk.wordChars((int)'a', (int)'z');
2N/A tk.wordChars((int)'0', (int)'9');
2N/A tk.wordChars((int)'&', (int)'&');
2N/A tk.wordChars((int)'*', (int)'*');
2N/A tk.wordChars((int)':', (int)':');
2N/A tk.wordChars((int)'-', (int)'-');
2N/A tk.wordChars((int)'_', (int)'_');
2N/A tk.wordChars((int)'$', (int)'$');
2N/A tk.wordChars((int)'+', (int)'+');
2N/A tk.wordChars((int)'@', (int)'@');
2N/A tk.wordChars((int)'.', (int)'.');
2N/A tk.wordChars((int)'|', (int)'|');
2N/A tk.wordChars((int)'<', (int)'<');
2N/A tk.wordChars((int)'>', (int)'>');
2N/A tk.wordChars((int)'~', (int)'~');
2N/A
2N/A }
2N/A
2N/A // Initialize tokenizer for parsing attribute name,
2N/A // attribute type and flags,
2N/A // and for boolean initializer lists.
2N/A
2N/A private void initIdChar(StreamTokenizer tk) {
2N/A
2N/A initForBase(tk);
2N/A initCommonToken(tk);
2N/A
2N/A // Need backslash for escaping.
2N/A
2N/A tk.wordChars((int)'\\', (int)'\\');
2N/A
2N/A // Attribute id, Type, flags, and boolean initialzers
2N/A // all ignore white space.
2N/A
2N/A tk.whitespaceChars((int)' ', (int)' ');
2N/A tk.whitespaceChars((int)'\t', (int)'\t');
2N/A
2N/A // Attribute part won't view newline as being significant.
2N/A
2N/A tk.eolIsSignificant(false);
2N/A
2N/A // Case is not folded.
2N/A
2N/A tk.lowerCaseMode(false);
2N/A }
2N/A
2N/A // Initialize tokenizer for parsing service type name.
2N/A // need to restrict characters.
2N/A
2N/A private void initSchemeIdChar(StreamTokenizer tk) {
2N/A
2N/A initForBase(tk);
2N/A
2N/A tk.wordChars((int)'A', (int)'Z');
2N/A tk.wordChars((int)'a', (int)'z');
2N/A tk.wordChars((int)'0', (int)'9');
2N/A tk.wordChars((int)'-', (int)'-');
2N/A tk.wordChars((int)'+', (int)'+');
2N/A tk.wordChars((int)'.', (int)'.'); // allows naming authority.
2N/A tk.wordChars((int)':', (int)':'); // for abstract and concrete type.
2N/A
2N/A // Scheme name, type, flags, and boolean initialzers
2N/A // all ignore white space.
2N/A
2N/A tk.whitespaceChars((int)' ', (int)' ');
2N/A tk.whitespaceChars((int)'\t', (int)'\t');
2N/A
2N/A // Scheme part won't view newline as being significant.
2N/A
2N/A tk.eolIsSignificant(false);
2N/A
2N/A // Case is not folded.
2N/A
2N/A tk.lowerCaseMode(false);
2N/A
2N/A }
2N/A
2N/A // Initialize tokenizer for string list parsing.
2N/A // Everything except '#' and ',' is recognized.
2N/A // Note that whitespace is significant, but
2N/A // EOL is ignored.
2N/A
2N/A private void initStringItemChar(StreamTokenizer tk) {
2N/A
2N/A initForBase(tk);
2N/A
2N/A tk.wordChars((int)'\t', (int)'\t');
2N/A tk.wordChars((int)' ', (int)'"');
2N/A // '#' goes here
2N/A tk.wordChars((int)'$', (int)'+');
2N/A // ',' goes here
2N/A tk.wordChars((int)'-', (int)'/');
2N/A tk.wordChars((int)'0', (int)'9');
2N/A tk.wordChars((int)':', (int)':');
2N/A // ';' goes here
2N/A tk.wordChars((int)'<', (int)'@');
2N/A tk.wordChars((int)'A', (int)'Z');
2N/A tk.wordChars((int)'[', (int)'`');
2N/A tk.wordChars((int)'a', (int)'z');
2N/A tk.wordChars((int)'{', (int)'~');
2N/A
2N/A // '%' is also reserved, but it is postprocessed
2N/A // after the string is collected.
2N/A
2N/A // Parse by lines to check when we've reached the end of the list.
2N/A
2N/A tk.whitespaceChars((int)'\r', (int)'\r');
2N/A tk.whitespaceChars((int)'\n', (int)'\n');
2N/A tk.eolIsSignificant(true);
2N/A
2N/A }
2N/A
2N/A // Initialize tokenizer for integer list parsing.
2N/A
2N/A private void initIntItemChar(StreamTokenizer tk) {
2N/A
2N/A initForBase(tk);
2N/A
2N/A tk.wordChars((int)'0', (int)'9');
2N/A tk.wordChars((int)'-', (int)'-');
2N/A tk.wordChars((int)'+', (int)'+');
2N/A
2N/A // Integer value list parsing ignores white space.
2N/A
2N/A tk.whitespaceChars((int)' ', (int)' ');
2N/A tk.whitespaceChars((int)'\t', (int)'\t');
2N/A
2N/A // Parse by lines so we can find the end.
2N/A
2N/A tk.whitespaceChars((int)'\r', (int)'\r');
2N/A tk.whitespaceChars((int)'\n', (int)'\n');
2N/A tk.eolIsSignificant(true);
2N/A
2N/A }
2N/A
2N/A // Boolean lists have same item syntax as scheme char.
2N/A
2N/A // Initialize main production parsing. The only
2N/A // significant token character is <NL> because
2N/A // parsing is done on a line-oriented basis.
2N/A
2N/A private void initFieldChar(StreamTokenizer tk) {
2N/A
2N/A initForBase(tk);
2N/A
2N/A tk.wordChars((int)'\t', (int)'\t');
2N/A tk.wordChars((int)' ', (int)'/');
2N/A tk.wordChars((int)'0', (int)'9');
2N/A tk.wordChars((int)':', (int)'@');
2N/A tk.wordChars((int)'A', (int)'Z');
2N/A tk.wordChars((int)'[', (int)'`');
2N/A tk.wordChars((int)'a', (int)'z');
2N/A tk.wordChars((int)'{', (int)'~');
2N/A
2N/A tk.whitespaceChars((int)'\r', (int)'\r');
2N/A tk.whitespaceChars((int)'\n', (int)'\n');
2N/A tk.eolIsSignificant(true);
2N/A }
2N/A
2N/A //
2N/A // Parsing methods.
2N/A //
2N/A
2N/A // Parse a template from the tokenizer.
2N/A
2N/A private void parseTemplate(StreamTokenizer tk)
2N/A throws ServiceLocationException {
2N/A
2N/A // First parse past the template attributes.
2N/A
2N/A parseTemplateAttributes(tk);
2N/A
2N/A // Finally, parse the attributes.
2N/A
2N/A parseAttributes(tk);
2N/A
2N/A }
2N/A
2N/A // Parse the template attributes from the tokenizer.
2N/A
2N/A private void parseTemplateAttributes(StreamTokenizer tk)
2N/A throws ServiceLocationException {
2N/A
2N/A int found = 0;
2N/A
2N/A // Parse each of the template attributes. Note that we are parsing
2N/A // the attribute value assignments, not definitions.
2N/A
2N/A try {
2N/A
2N/A do {
2N/A
2N/A found = found | parseTemplateAttribute(tk, found);
2N/A
2N/A } while (found != TEMPLATE_FOUND);
2N/A
2N/A } catch (IOException ex) {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.INTERNAL_SYSTEM_ERROR,
2N/A "template_io_error",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A
2N/A }
2N/A }
2N/A
2N/A // Parse a template attribute.
2N/A
2N/A private int parseTemplateAttribute(StreamTokenizer tk, int found)
2N/A throws ServiceLocationException, IOException {
2N/A
2N/A // Get line including id and equals.
2N/A
2N/A int tt = tk.nextToken();
2N/A
2N/A if (tt != StreamTokenizer.TT_WORD) {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_assign_error",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A }
2N/A
2N/A // Get tokenizer for id and potential value line.
2N/A
2N/A StringReader rdr = new StringReader(tk.sval);
2N/A StreamTokenizer stk = new StreamTokenizer(rdr);
2N/A
2N/A initIdChar(stk);
2N/A
2N/A // Make sure newline is there.
2N/A
2N/A if ((tt = tk.nextToken()) == StreamTokenizer.TT_EOF) {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_end_error",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A
2N/A }
2N/A
2N/A if (tt != StreamTokenizer.TT_EOL) {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_unk_token",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A
2N/A }
2N/A
2N/A
2N/A // Parse off id.
2N/A
2N/A if ((tt = stk.nextToken()) != StreamTokenizer.TT_WORD) {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_missing_id",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A }
2N/A
2N/A String id = stk.sval;
2N/A boolean duplicate = false;
2N/A int mask = 0;
2N/A
2N/A // Check for the equals.
2N/A
2N/A if ((tt = stk.nextToken()) != TT_EQUALS) {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_missing_eq ",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A
2N/A }
2N/A
2N/A // Depending on the id, parse the rest.
2N/A
2N/A if (id.equalsIgnoreCase(SLPTemplateRegistry.SERVICE_ATTR_ID)) {
2N/A
2N/A if ((found & SERVICE_MASK) == 0) {
2N/A
2N/A // Just need to parse off the service type.
2N/A
2N/A if ((tt = stk.nextToken()) != StreamTokenizer.TT_WORD) {
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_srv_type_err",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A }
2N/A
2N/A // Check for characters which are not alphanumerics, + and -.
2N/A // Service type names are more heavily restricted.
2N/A
2N/A StreamTokenizer sttk =
2N/A new StreamTokenizer(new StringReader(stk.sval));
2N/A
2N/A initSchemeIdChar(sttk);
2N/A
2N/A if (sttk.nextToken() != StreamTokenizer.TT_WORD ||
2N/A !stk.sval.equals(sttk.sval)) {
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_srv_type_err",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A
2N/A }
2N/A
2N/A // Need to prefix with "serivce:".
2N/A
2N/A String typeName = sttk.sval;
2N/A
2N/A if (!typeName.startsWith(Defaults.SERVICE_PREFIX+":")) {
2N/A typeName = Defaults.SERVICE_PREFIX+":"+typeName;
2N/A
2N/A }
2N/A
2N/A // Set service type instance variable.
2N/A
2N/A serviceType = new ServiceType(typeName);
2N/A
2N/A // Check for extra stuff.
2N/A
2N/A if ((tt = stk.nextToken()) != StreamTokenizer.TT_EOF) {
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_srv_type_err",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A }
2N/A
2N/A mask = SERVICE_MASK;
2N/A } else {
2N/A
2N/A duplicate = true;
2N/A }
2N/A } else if (id.equalsIgnoreCase(SLPTemplateRegistry.VERSION_ATTR_ID)) {
2N/A
2N/A if ((found & VERSION_MASK) == 0) {
2N/A
2N/A // Just need to parse off the version number.
2N/A
2N/A if ((tt = stk.nextToken()) != StreamTokenizer.TT_WORD) {
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_vers_err",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A }
2N/A
2N/A // Make sure it's a valid version number.
2N/A
2N/A String version = stk.sval;
2N/A
2N/A if (version.indexOf(TT_PERIOD) == -1) {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_vers_mssing",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A
2N/A }
2N/A
2N/A try {
2N/A
2N/A new Float(version);
2N/A } catch (NumberFormatException ex) {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_vers_err",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A
2N/A }
2N/A
2N/A this.version = version;
2N/A
2N/A // Check for extra stuff.
2N/A
2N/A if ((tt = stk.nextToken()) != StreamTokenizer.TT_EOF) {
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_vers_err",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A }
2N/A
2N/A mask = VERSION_MASK;
2N/A } else {
2N/A
2N/A duplicate = true;
2N/A }
2N/A } else if (id.equalsIgnoreCase(
2N/A SLPTemplateRegistry.DESCRIPTION_ATTR_ID)) {
2N/A
2N/A // Make sure there is nothing else on that line.
2N/A
2N/A if (stk.nextToken() != StreamTokenizer.TT_EOF) {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_attr_syntax",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A }
2N/A
2N/A if ((found & DESCRIPTION_MASK) == 0) {
2N/A
2N/A // Need to continue parsing help text until we reach a blank
2N/A // line.
2N/A
2N/A String helpText = "";
2N/A
2N/A do {
2N/A int ptt = tt;
2N/A tt = tk.nextToken();
2N/A
2N/A if (tt == StreamTokenizer.TT_WORD) {
2N/A
2N/A helpText = helpText + tk.sval + "\n";
2N/A
2N/A } else if (tt == StreamTokenizer.TT_EOL) {
2N/A
2N/A // If previous token was end of line, quit.
2N/A
2N/A if (ptt == StreamTokenizer.TT_EOL) {
2N/A
2N/A // Store any text first.
2N/A
2N/A if (helpText.length() > 0) {
2N/A description = helpText;
2N/A
2N/A }
2N/A
2N/A tk.pushBack(); // so same as above
2N/A
2N/A break;
2N/A }
2N/A } else if (tt == StreamTokenizer.TT_EOF) {
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_end_error",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A
2N/A } else {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_unk_token",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A
2N/A }
2N/A
2N/A } while (true);
2N/A
2N/A mask = DESCRIPTION_MASK;
2N/A } else {
2N/A
2N/A duplicate = true;
2N/A }
2N/A } else if (id.equalsIgnoreCase(
2N/A SLPTemplateRegistry.SERVICE_URL_ATTR_ID)) {
2N/A
2N/A if ((found & URL_PATH_RULES_MASK) == 0) {
2N/A
2N/A String serviceURLGrammer = "";
2N/A
2N/A // Pull everything out of the rdr StringReader until empty.
2N/A
2N/A int ic;
2N/A
2N/A while ((ic = rdr.read()) != -1) {
2N/A serviceURLGrammer += (char)ic;
2N/A
2N/A }
2N/A
2N/A serviceURLGrammer += "\n";
2N/A
2N/A // Need to continue parsing service URL syntax until we
2N/A // reach a blank line.
2N/A
2N/A tt = StreamTokenizer.TT_EOL;
2N/A
2N/A do {
2N/A int ptt = tt;
2N/A tt = tk.nextToken();
2N/A
2N/A if (tt == StreamTokenizer.TT_WORD) {
2N/A
2N/A serviceURLGrammer = serviceURLGrammer + tk.sval + "\n";
2N/A
2N/A } else if (tt == StreamTokenizer.TT_EOL) {
2N/A
2N/A // If previous token was end of line, quit.
2N/A
2N/A if (ptt == StreamTokenizer.TT_EOL) {
2N/A
2N/A // Store any text first.
2N/A
2N/A if (serviceURLGrammer.length() > 0) {
2N/A URLSyntax = serviceURLGrammer;
2N/A
2N/A }
2N/A
2N/A tk.pushBack(); // so same as above.
2N/A
2N/A break;
2N/A }
2N/A } else if (tt == StreamTokenizer.TT_EOF) {
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_end_error",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A
2N/A } else {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_unk_token",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A
2N/A }
2N/A
2N/A } while (true);
2N/A
2N/A mask = URL_PATH_RULES_MASK;
2N/A } else {
2N/A
2N/A duplicate = true;
2N/A }
2N/A } else {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_nontattribute_err",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A
2N/A }
2N/A
2N/A // Throw exception if a duplicate definition was detected.
2N/A
2N/A if (duplicate) {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_dup_def",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A
2N/A }
2N/A
2N/A
2N/A // Make sure the assignment ends with a blank line.
2N/A
2N/A if ((tt = tk.nextToken()) != StreamTokenizer.TT_EOL) {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_attr_syntax",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A
2N/A }
2N/A
2N/A return mask;
2N/A
2N/A }
2N/A
2N/A
2N/A // Parse the attributes from the tokenizer.
2N/A
2N/A private void parseAttributes(StreamTokenizer tk)
2N/A throws ServiceLocationException {
2N/A
2N/A try {
2N/A
2N/A do {
2N/A
2N/A // Check if at end of file yet.
2N/A
2N/A int tt = tk.nextToken();
2N/A
2N/A if (tt == StreamTokenizer.TT_EOF) {
2N/A break;
2N/A }
2N/A
2N/A // If not, push token back so we can get it next time.
2N/A
2N/A tk.pushBack();
2N/A
2N/A // Parse off the attribute descriptor.
2N/A
2N/A AttributeDescriptor attDesc = parseAttribute(tk);
2N/A
2N/A // Check whether default values, if any, are correct.
2N/A
2N/A checkDefaultValues(attDesc);
2N/A
2N/A // If the attribute already exists, then throw exception.
2N/A // We could arguably replace existing, but it might
2N/A // suprise the user.
2N/A
2N/A String attrId = attDesc.getId().toLowerCase();
2N/A
2N/A if (attributeDescriptors.get(attrId) != null) {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_dup_def",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A
2N/A }
2N/A
2N/A // Add the attribute to the descriptor table.
2N/A
2N/A attributeDescriptors.put(attrId, attDesc);
2N/A
2N/A } while (true);
2N/A
2N/A } catch (IOException ex) {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.INTERNAL_SYSTEM_ERROR,
2N/A "template_io_error",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A }
2N/A
2N/A }
2N/A
2N/A // Parse a single attribute description from the tokenizer.
2N/A
2N/A private AttributeDescriptor
2N/A parseAttribute(StreamTokenizer tk) throws ServiceLocationException {
2N/A
2N/A AttributeDescriptor attDesc = new AttributeDescriptor();
2N/A int lineno = 0;
2N/A
2N/A try {
2N/A
2N/A // Parse the string for attribute id, type, and flags.
2N/A
2N/A lineno = tk.lineno();
2N/A
2N/A int tt = tk.nextToken();
2N/A
2N/A if (tt != StreamTokenizer.TT_WORD) {
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_attr_syntax",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A }
2N/A
2N/A StreamTokenizer stk =
2N/A new StreamTokenizer(new StringReader(tk.sval));
2N/A
2N/A initIdChar(stk);
2N/A
2N/A // Parse the attribute id.
2N/A
2N/A parseId(stk, attDesc, lineno);
2N/A
2N/A // Parse the type and flags.
2N/A
2N/A parseTypeAndFlags(stk, attDesc, lineno);
2N/A
2N/A tt = tk.nextToken();
2N/A
2N/A if (tt == StreamTokenizer.TT_EOF) {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_end_error",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A
2N/A }
2N/A
2N/A if (tt != StreamTokenizer.TT_EOL) {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_unk_token",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A
2N/A }
2N/A
2N/A // Parse initial values.
2N/A
2N/A if (!attDesc.getIsKeyword()) {
2N/A
2N/A String tok = "";
2N/A
2N/A // Read in entire list.
2N/A
2N/A do {
2N/A int ptt = tt;
2N/A lineno = tk.lineno();
2N/A tt = tk.nextToken();
2N/A
2N/A if (tt == StreamTokenizer.TT_WORD) {
2N/A
2N/A // Trim line, check for '#', indicating end of list.
2N/A
2N/A String line = tk.sval.trim();
2N/A
2N/A if (line.charAt(0) == TT_FIELD) {
2N/A // it's help text already.
2N/A
2N/A if (tok.length() > 0) {
2N/A stk =
2N/A new StreamTokenizer(new StringReader(tok));
2N/A parseDefaultValues(stk, attDesc, lineno);
2N/A }
2N/A
2N/A tk.pushBack();
2N/A break;
2N/A
2N/A } else {
2N/A
2N/A // Otherwise concatenate onto growing list.
2N/A
2N/A tok = tok + line;
2N/A
2N/A }
2N/A
2N/A } else if (tt == StreamTokenizer.TT_EOL) {
2N/A
2N/A if (ptt == StreamTokenizer.TT_EOL) {
2N/A // end of attribute definition.
2N/A
2N/A // Process any accumulated list.
2N/A
2N/A if (tok.length() > 0) {
2N/A stk =
2N/A new StreamTokenizer(new StringReader(tok));
2N/A parseDefaultValues(stk, attDesc, lineno);
2N/A }
2N/A
2N/A return attDesc;
2N/A
2N/A }
2N/A } else if (tt == StreamTokenizer.TT_EOF) {
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_end_error",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A
2N/A } else {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_unk_token",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A
2N/A }
2N/A
2N/A } while (true);
2N/A
2N/A } else {
2N/A attDesc.setDefaultValues(null);
2N/A attDesc.setAllowedValues(null);
2N/A
2N/A // Check for end of definition.
2N/A
2N/A if ((tt = tk.nextToken()) == StreamTokenizer.TT_EOL) {
2N/A return attDesc;
2N/A
2N/A } else if (tt == StreamTokenizer.TT_WORD) {
2N/A
2N/A // Check for start of help text.
2N/A
2N/A String line = tk.sval.trim();
2N/A
2N/A if (line.charAt(0) != TT_FIELD) {
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_attr_syntax",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A
2N/A } else {
2N/A
2N/A tk.pushBack();
2N/A
2N/A }
2N/A
2N/A } else if (tt == StreamTokenizer.TT_EOF) {
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_end_error",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A
2N/A } else {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_unk_token",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A
2N/A }
2N/A }
2N/A
2N/A
2N/A // Parse help text.
2N/A
2N/A String helpText = "";
2N/A
2N/A do {
2N/A int ptt = tt;
2N/A lineno = tk.lineno();
2N/A tt = tk.nextToken();
2N/A
2N/A if (tt == StreamTokenizer.TT_WORD) {
2N/A
2N/A // Check for end of help text.
2N/A
2N/A String line = tk.sval.trim();
2N/A
2N/A if (line.charAt(0) == TT_FIELD) {
2N/A
2N/A // Help text is collected verbatim after '#'.
2N/A
2N/A helpText =
2N/A helpText + line.substring(1) + "\n";
2N/A
2N/A } else {
2N/A
2N/A // We've reached the end of the help text. Store it
2N/A // and break out of the loop.
2N/A
2N/A if (helpText.length() > 0) {
2N/A attDesc.setDescription(helpText);
2N/A }
2N/A
2N/A tk.pushBack();
2N/A break;
2N/A
2N/A }
2N/A
2N/A } else if (tt == StreamTokenizer.TT_EOL ||
2N/A tt == StreamTokenizer.TT_EOF) {
2N/A
2N/A // If previous token was end of line, quit.
2N/A
2N/A if (ptt == StreamTokenizer.TT_EOL) {
2N/A
2N/A // Store any text first.
2N/A
2N/A if (helpText.length() > 0) {
2N/A attDesc.setDescription(helpText);
2N/A }
2N/A
2N/A // If this is a keyword attribute, set the allowed
2N/A // values list to null.
2N/A
2N/A if (attDesc.getIsKeyword()) {
2N/A attDesc.setAllowedValues(null);
2N/A }
2N/A
2N/A return attDesc;
2N/A
2N/A } else if (tt == StreamTokenizer.TT_EOF) {
2N/A
2N/A // Error if previous token wasn't EOL.
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_end_error",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A }
2N/A
2N/A } else {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_unk_token",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A }
2N/A
2N/A } while (true);
2N/A
2N/A // Parse allowed values.
2N/A
2N/A if (!attDesc.getIsKeyword()) {
2N/A
2N/A String tok = "";
2N/A
2N/A // Read in entire list.
2N/A
2N/A do {
2N/A int ptt = tt;
2N/A lineno = tk.lineno();
2N/A tt = tk.nextToken();
2N/A
2N/A if (tt == StreamTokenizer.TT_WORD) {
2N/A
2N/A // Concatenate onto growing list.
2N/A
2N/A tok = tok + tk.sval;
2N/A
2N/A } else if (tt == StreamTokenizer.TT_EOL) {
2N/A
2N/A if (ptt == StreamTokenizer.TT_EOL) {
2N/A // end of attribute definition.
2N/A
2N/A // Process any accumulated list.
2N/A
2N/A if (tok.length() > 0) {
2N/A stk =
2N/A new StreamTokenizer(new StringReader(tok));
2N/A parseAllowedValues(stk, attDesc, lineno);
2N/A }
2N/A
2N/A return attDesc;
2N/A
2N/A }
2N/A } else if (tt == StreamTokenizer.TT_EOF) {
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_end_error",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A
2N/A } else {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_unk_token",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A }
2N/A
2N/A } while (true);
2N/A
2N/A } else {
2N/A
2N/A // Error. Keyword attribute should have ended during help text
2N/A // parsing or before.
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_attr_syntax",
2N/A new Object[] {Integer.toString(tk.lineno())});
2N/A }
2N/A
2N/A } catch (IOException ex) {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.INTERNAL_SYSTEM_ERROR,
2N/A "template_io_error",
2N/A new Object[] {
2N/A Integer.toString(tk.lineno()),
2N/A ex.getMessage()});
2N/A }
2N/A
2N/A }
2N/A
2N/A // Check whether the default values, if any, are correct.
2N/A
2N/A private void checkDefaultValues(AttributeDescriptor attDesc)
2N/A throws ServiceLocationException {
2N/A
2N/A // Don't bother if it's a keyword attribute, parsing has checked.
2N/A
2N/A if (attDesc.getIsKeyword()) {
2N/A return;
2N/A }
2N/A
2N/A Enumeration init = attDesc.getDefaultValues();
2N/A Enumeration en = attDesc.getAllowedValues();
2N/A Vector allowed = new Vector();
2N/A String attDescType = attDesc.getValueType();
2N/A
2N/A // First, collect the allowed values.
2N/A
2N/A while (en.hasMoreElements()) {
2N/A Object allval = en.nextElement();
2N/A
2N/A // Lower case strings and create opaques for comparison
2N/A // if type is opaque.
2N/A
2N/A if (attDescType.equals(JAVA_STRING_TYPE)) {
2N/A allval = ((String)allval).toLowerCase();
2N/A
2N/A } else if (attDescType.equals(JAVA_OPAQUE_TYPE)) {
2N/A allval = new Opaque((byte[])allval);
2N/A
2N/A }
2N/A
2N/A allowed.addElement(allval);
2N/A }
2N/A
2N/A // Now compare the allowed with the initial.
2N/A
2N/A if (allowed.size() > 0) {
2N/A
2N/A // Error if allowed is restricted but no initializers.
2N/A
2N/A if (!init.hasMoreElements()) {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_no_init",
2N/A new Object[] {attDesc.getId()});
2N/A
2N/A }
2N/A
2N/A Object val = null;
2N/A
2N/A // Compare init values with allowed.
2N/A
2N/A while (init.hasMoreElements()) {
2N/A Object test = init.nextElement();
2N/A val = test; // for exception..
2N/A
2N/A if (attDescType.equals(JAVA_STRING_TYPE)) {
2N/A test = ((String)test).toLowerCase();
2N/A
2N/A } else if (attDescType.equals(JAVA_OPAQUE_TYPE)) {
2N/A test = new Opaque((byte[])test);
2N/A
2N/A }
2N/A
2N/A if (allowed.indexOf(test) != -1) {
2N/A return; // found it!
2N/A }
2N/A }
2N/A // Initializer wasn't found.
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_wrong_init",
2N/A new Object[] {
2N/A val.toString(), attDesc.getId()});
2N/A }
2N/A }
2N/A
2N/A // Parse the attribute's id string.
2N/A
2N/A private void parseId(StreamTokenizer tk,
2N/A AttributeDescriptor attDesc,
2N/A int baseLineno)
2N/A throws ServiceLocationException, IOException {
2N/A
2N/A // Parse the attribute's identifier tag.
2N/A
2N/A String id = parseWord(tk, baseLineno);
2N/A
2N/A int tt = tk.nextToken();
2N/A
2N/A // Parse the separator.
2N/A
2N/A if (tt != TT_EQUALS) {
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_attr_syntax",
2N/A new Object[] {
2N/A Integer.toString(tk.lineno() + baseLineno)});
2N/A
2N/A }
2N/A
2N/A // Expand out any escaped ``#''. It won't be handled by
2N/A // SLA.
2N/A
2N/A id = unescapeHash(id);
2N/A
2N/A // Expand out character escapes.
2N/A
2N/A id =
2N/A ServiceLocationAttribute.unescapeAttributeString(id, true);
2N/A
2N/A
2N/A attDesc.setId(id);
2N/A }
2N/A
2N/A // Parse the attribute's type and flags.
2N/A
2N/A private void
2N/A parseTypeAndFlags(StreamTokenizer tk,
2N/A AttributeDescriptor attDesc,
2N/A int baseLineno)
2N/A throws ServiceLocationException, IOException {
2N/A
2N/A int existingFlags = 0;
2N/A
2N/A // Parse the attribute's type.
2N/A
2N/A String type = parseWord(tk, baseLineno);
2N/A
2N/A checkAndAddType(type, attDesc, tk.lineno() + baseLineno);
2N/A
2N/A // Parse the flags.
2N/A
2N/A do {
2N/A
2N/A // Check if any flags are left.
2N/A
2N/A if (tk.nextToken() == StreamTokenizer.TT_EOF) {
2N/A break;
2N/A
2N/A } else {
2N/A tk.pushBack();
2N/A }
2N/A
2N/A int lineno = tk.lineno();
2N/A
2N/A // Parse the flag.
2N/A
2N/A String flag = parseWord(tk, baseLineno);
2N/A
2N/A // Error if flags with keyword.
2N/A
2N/A if (attDesc.getIsKeyword()) {
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_attr_syntax",
2N/A new Object[] {
2N/A Integer.toString(tk.lineno() + baseLineno)});
2N/A }
2N/A
2N/A
2N/A // Check and assign it to the attribute.
2N/A
2N/A existingFlags =
2N/A existingFlags | checkAndAddFlag(flag,
2N/A existingFlags,
2N/A attDesc,
2N/A baseLineno + lineno);
2N/A
2N/A } while (true);
2N/A }
2N/A
2N/A // Parse the attribute's initial value(s).
2N/A
2N/A private void parseDefaultValues(StreamTokenizer tk,
2N/A AttributeDescriptor attDesc,
2N/A int baseLineno)
2N/A throws ServiceLocationException, IOException {
2N/A
2N/A // First get the vector of initial values.
2N/A
2N/A Vector vals = parseValueList(tk, attDesc, baseLineno);
2N/A
2N/A // Check whether it works for this attribute. Type
2N/A // checking will be done by value list parsing.
2N/A
2N/A if (!attDesc.getIsMultivalued() && vals.size() > 1) {
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_attr_syntax",
2N/A new Object[] {
2N/A Integer.toString(tk.lineno() + baseLineno)});
2N/A }
2N/A
2N/A attDesc.setDefaultValues(vals);
2N/A }
2N/A
2N/A // Parse the attribute's allowed values.
2N/A
2N/A private void
2N/A parseAllowedValues(StreamTokenizer tk,
2N/A AttributeDescriptor attDesc,
2N/A int baseLineno)
2N/A throws ServiceLocationException, IOException {
2N/A
2N/A // First get the vector of all allowed values.
2N/A
2N/A Vector vals = parseValueList(tk, attDesc, baseLineno);
2N/A
2N/A // Now set the allowed value vector.
2N/A
2N/A attDesc.setAllowedValues(vals);
2N/A }
2N/A
2N/A // Parse a value list.
2N/A
2N/A private Vector parseValueList(StreamTokenizer stk,
2N/A AttributeDescriptor attDesc,
2N/A int baseLineno)
2N/A throws ServiceLocationException, IOException {
2N/A
2N/A Vector req = new Vector();
2N/A
2N/A // Set up the tokenizer according to the type of the
2N/A // attribute.
2N/A
2N/A String type = attDesc.getValueType();
2N/A
2N/A if (type.equals(JAVA_STRING_TYPE) || type.equals(JAVA_OPAQUE_TYPE)) {
2N/A initStringItemChar(stk);
2N/A } else if (type.equals(JAVA_INTEGER_TYPE)) {
2N/A initIntItemChar(stk);
2N/A } else if (type.equals(JAVA_BOOLEAN_TYPE)) {
2N/A initIdChar(stk);
2N/A }
2N/A
2N/A // Parse through a potentially multivalued value list.
2N/A
2N/A boolean wordRequired = true; // true when a word is required,
2N/A // false when a comma required.
2N/A boolean syntaxError = false;
2N/A String reqTok = "";
2N/A int lineno = 0;
2N/A
2N/A do {
2N/A int tt = stk.nextToken();
2N/A lineno = stk.lineno() + baseLineno;
2N/A
2N/A if (tt == StreamTokenizer.TT_WORD) {
2N/A
2N/A // If a word isn't required, then the case is
2N/A // "token token" and is an error.
2N/A
2N/A if (!wordRequired) {
2N/A syntaxError = true;
2N/A }
2N/A
2N/A reqTok = stk.sval.trim();
2N/A
2N/A // Convert the value to the proper object.
2N/A
2N/A Object reqVal = convertValue(type, reqTok, baseLineno);
2N/A req.addElement(reqVal);
2N/A
2N/A wordRequired = false;
2N/A
2N/A } else if (tt == StreamTokenizer.TT_EOF) {
2N/A
2N/A // If a word is required, then list ends with
2N/A // a comma, so error.
2N/A
2N/A if (wordRequired) {
2N/A syntaxError = true;
2N/A }
2N/A
2N/A break;
2N/A
2N/A } else if (tt == TT_COMMA) {
2N/A
2N/A // If a word is required, then error. The case is ",,".
2N/A
2N/A if (wordRequired) {
2N/A syntaxError = true;
2N/A break;
2N/A }
2N/A
2N/A // Otherwise, the next token must be a word.
2N/A
2N/A wordRequired = true;
2N/A
2N/A } else {
2N/A
2N/A // No other tokens are allowed.
2N/A
2N/A syntaxError = true;
2N/A break;
2N/A }
2N/A
2N/A } while (true);
2N/A
2N/A if (syntaxError) {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_attr_syntax",
2N/A new Object[] {Integer.toString(lineno)});
2N/A }
2N/A
2N/A return req;
2N/A
2N/A }
2N/A
2N/A // Check the type and add it to the attribute descriptor.
2N/A
2N/A private void checkAndAddType(String type,
2N/A AttributeDescriptor attDesc,
2N/A int lineno)
2N/A throws ServiceLocationException {
2N/A
2N/A // Check token against recognized types.
2N/A
2N/A if (type.equalsIgnoreCase(STRING_TYPE)) {
2N/A attDesc.setValueType(JAVA_STRING_TYPE);
2N/A
2N/A } else if (type.equalsIgnoreCase(INTEGER_TYPE)) {
2N/A attDesc.setValueType(JAVA_INTEGER_TYPE);
2N/A
2N/A } else if (type.equalsIgnoreCase(BOOLEAN_TYPE)) {
2N/A attDesc.setValueType(JAVA_BOOLEAN_TYPE);
2N/A
2N/A } else if (type.equalsIgnoreCase(OPAQUE_TYPE)) {
2N/A attDesc.setValueType(JAVA_OPAQUE_TYPE);
2N/A
2N/A } else if (type.equalsIgnoreCase(KEYWORD_TYPE)) {
2N/A attDesc.setIsKeyword(true);
2N/A
2N/A } else {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_not_slp_type",
2N/A new Object[] {Integer.toString(lineno)});
2N/A }
2N/A
2N/A }
2N/A
2N/A // Check the flag and add it to the attribute descriptor.
2N/A
2N/A private int checkAndAddFlag(String flag,
2N/A int matched,
2N/A AttributeDescriptor attDesc,
2N/A int lineno)
2N/A throws ServiceLocationException {
2N/A
2N/A boolean duplicate = false;
2N/A
2N/A // We depend on the attribute descriptor being initialized to
2N/A // nothing, i.e. false for all flags and for keyword.
2N/A
2N/A if (flag.equalsIgnoreCase(MULTIPLE_FLAG)) {
2N/A
2N/A if ((matched & MULTIPLE_MASK) != 0) {
2N/A duplicate = true;
2N/A
2N/A } else {
2N/A
2N/A // Check for boolean. Booleans may not have
2N/A // multiple values.
2N/A
2N/A if (attDesc.getValueType().equals(JAVA_BOOLEAN_TYPE)) {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_boolean_multi",
2N/A new Object[] {Integer.toString(lineno)});
2N/A }
2N/A
2N/A attDesc.setIsMultivalued(true);
2N/A return MULTIPLE_MASK;
2N/A
2N/A }
2N/A
2N/A } else if (flag.equalsIgnoreCase(LITERAL_FLAG)) {
2N/A
2N/A if ((matched & LITERAL_MASK) != 0) {
2N/A duplicate = true;
2N/A
2N/A } else {
2N/A attDesc.setIsLiteral(true);
2N/A return LITERAL_MASK;
2N/A }
2N/A
2N/A } else if (flag.equalsIgnoreCase(EXPLICIT_FLAG)) {
2N/A
2N/A if ((matched & EXPLICIT_MASK) != 0) {
2N/A duplicate = true;
2N/A
2N/A } else {
2N/A attDesc.setRequiresExplicitMatch(true);
2N/A return EXPLICIT_MASK;
2N/A }
2N/A
2N/A } else if (flag.equalsIgnoreCase(OPTIONAL_FLAG)) {
2N/A
2N/A if ((matched & OPTIONAL_MASK) != 0) {
2N/A duplicate = true;
2N/A
2N/A } else {
2N/A attDesc.setIsOptional(true);
2N/A return OPTIONAL_MASK;
2N/A }
2N/A
2N/A } else {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_invalid_attr_flag",
2N/A new Object[] {Integer.toString(lineno)});
2N/A }
2N/A
2N/A
2N/A if (duplicate) {
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_dup_attr_flag",
2N/A new Object[] {Integer.toString(lineno)});
2N/A }
2N/A
2N/A return 0; // never happens.
2N/A }
2N/A
2N/A // Parse a word out of the tokenizer. The exact characters
2N/A // will depend on what the syntax tables have been set to.
2N/A
2N/A private String parseWord(StreamTokenizer tk, int baseLineno)
2N/A throws ServiceLocationException, IOException {
2N/A
2N/A int tt = tk.nextToken();
2N/A
2N/A if (tt == StreamTokenizer.TT_WORD) {
2N/A return (tk.sval);
2N/A
2N/A } else {
2N/A
2N/A String errorToken = "";
2N/A
2N/A // Report the erroneous characters.
2N/A
2N/A if (tt == StreamTokenizer.TT_NUMBER) {
2N/A errorToken = Double.toString(tk.nval);
2N/A } else if (tt == StreamTokenizer.TT_EOL) {
2N/A errorToken = "<end of line>";
2N/A } else if (tt == StreamTokenizer.TT_EOF) {
2N/A errorToken = "<end of file>";
2N/A } else {
2N/A errorToken = (new Character((char)tt)).toString();
2N/A }
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_invalid_tok",
2N/A new Object[] {
2N/A Integer.toString(tk.lineno() + baseLineno)});
2N/A
2N/A }
2N/A
2N/A }
2N/A
2N/A // Convert a value list token to the value.
2N/A
2N/A private Object convertValue(String type,
2N/A String reqTok,
2N/A int lineno)
2N/A throws ServiceLocationException,
2N/A IOException {
2N/A
2N/A Object reqVal = null;
2N/A
2N/A if (type.equals(JAVA_STRING_TYPE)) {
2N/A
2N/A // Expand out any escaped ``#''. It won't be handled by
2N/A // SLA.
2N/A
2N/A reqTok = unescapeHash(reqTok);
2N/A
2N/A // Expand out character escapes.
2N/A
2N/A reqVal =
2N/A ServiceLocationAttribute.unescapeAttributeString(reqTok,
2N/A false);
2N/A
2N/A } else if (type.equals(JAVA_INTEGER_TYPE)) {
2N/A
2N/A try {
2N/A
2N/A reqVal = Integer.valueOf(reqTok);
2N/A
2N/A } catch (NumberFormatException ex) {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_expect_int",
2N/A new Object[] {
2N/A Integer.toString(lineno), reqTok });
2N/A }
2N/A } else if (type.equals(JAVA_BOOLEAN_TYPE)) {
2N/A
2N/A // Boolean.valueOf() doesn't handle this properly.
2N/A
2N/A if (reqTok.equalsIgnoreCase(TRUE_TOKEN)) {
2N/A
2N/A reqVal = new Boolean(true);
2N/A
2N/A } else if (reqTok.equalsIgnoreCase(FALSE_TOKEN)) {
2N/A
2N/A reqVal = new Boolean(false);
2N/A
2N/A } else {
2N/A
2N/A throw
2N/A new ServiceLocationException(
2N/A ServiceLocationException.PARSE_ERROR,
2N/A "template_expect_bool",
2N/A new Object[] {
2N/A Integer.toString(lineno), reqTok});
2N/A }
2N/A } else if (type.equals(JAVA_OPAQUE_TYPE)) {
2N/A
2N/A reqVal = Opaque.unescapeByteArray(reqTok);
2N/A
2N/A } else {
2N/A
2N/A Assert.slpassert(false,
2N/A "template_attr_desc",
2N/A new Object[0]);
2N/A }
2N/A
2N/A return reqVal;
2N/A }
2N/A
2N/A // Expand out any escaped hashes. Not handled by SLA.
2N/A
2N/A private String unescapeHash(String str) {
2N/A
2N/A StringBuffer buf = new StringBuffer();
2N/A int len = ESC_HASH.length();
2N/A int i, j = 0;
2N/A
2N/A for (i = str.indexOf(ESC_HASH, j);
2N/A i != -1;
2N/A i = str.indexOf(ESC_HASH, j)) {
2N/A
2N/A buf.append(str.substring(j, i));
2N/A buf.append(HASH);
2N/A j = i + len;
2N/A }
2N/A
2N/A len = str.length();
2N/A
2N/A if (j < len) {
2N/A buf.append(str.substring(j, len));
2N/A
2N/A }
2N/A
2N/A return buf.toString();
2N/A }
2N/A
2N/A}