1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 1999-2001 by Sun Microsystems, Inc. 23 * All rights reserved. 24 * 25 */ 26 27 // AttributeVerifier.java: An attribute verifier for SLP attributes. 28 // Author: James Kempf 29 // Created On: Thu Jun 19 10:51:32 1997 30 // Last Modified By: James Kempf 31 // Last Modified On: Mon Nov 9 10:21:02 1998 32 // Update Count: 200 33 // 34 35 package com.sun.slp; 36 37 import java.util.*; 38 import java.io.*; 39 40 /** 41 * The AttributeVerifier class implements the ServiceLocationAttributeVerifier 42 * interface, but without committment to a particular mechanism for 43 * obtaining the template defintion. Subclasses provide the mechanism, 44 * and pass in the template to the parent as a Reader during object 45 * creation. The AttributeVerifier class parses tokens from the Reader and 46 * constructs the attribute descriptor objects describing the attribute. These 47 * are used during verification of the attribute. The AttributeVerifier 48 * and implementations of the attribute descriptors are free to optimize 49 * space utilization by lazily evaluating portions of the attribute 50 * template. 51 * 52 * @author James Kempf 53 * 54 */ 55 56 class AttributeVerifier 57 extends Object 58 implements ServiceLocationAttributeVerifier { 59 60 // Template specific escape. 61 62 private static final String ESC_HASH = "\\23"; 63 private static final String HASH = "#"; 64 65 // Number of template attributes. 66 67 private static final int TEMPLATE_ATTR_NO = 5; 68 69 // Bitfields for found template attributes. 70 71 private static final int SERVICE_MASK = 0x01; 72 private static final int VERSION_MASK = 0x02; 73 private static final int DESCRIPTION_MASK = 0x08; 74 private static final int URL_PATH_RULES_MASK = 0x10; 75 76 // When all template attribute assignments are found. 77 78 private static final int TEMPLATE_FOUND = (SERVICE_MASK | 79 VERSION_MASK | 80 DESCRIPTION_MASK | 81 URL_PATH_RULES_MASK); 82 83 // These are the valid SLP types. 84 85 private static final String INTEGER_TYPE = "integer"; 86 private static final String STRING_TYPE = "string"; 87 private static final String BOOLEAN_TYPE = "boolean"; 88 private static final String OPAQUE_TYPE = "opaque"; 89 private static final String KEYWORD_TYPE = "keyword"; 90 91 // These are the corresponding Java types. Package public so 92 // others (SLPConfig for example) can get at them. 93 94 static final String JAVA_STRING_TYPE = 95 "java.lang.String"; 96 static final String JAVA_INTEGER_TYPE = 97 "java.lang.Integer"; 98 static final String JAVA_BOOLEAN_TYPE = 99 "java.lang.Boolean"; 100 static final String JAVA_OPAQUE_TYPE = 101 "[B"; 102 103 // Tokens for boolean values. 104 105 private static final String TRUE_TOKEN = "true"; 106 private static final String FALSE_TOKEN = "false"; 107 108 // This is the number of flags. 109 110 private static final int FLAG_NO = 4; 111 112 // These are the flags. 113 114 private static final String MULTIPLE_FLAG = "m"; 115 private static final String LITERAL_FLAG = "l"; 116 private static final String EXPLICIT_FLAG = "x"; 117 private static final String OPTIONAL_FLAG = "o"; 118 119 // These masks help determine whether the flags have been duplicated. 120 121 private static final byte MULTIPLE_MASK = 0x01; 122 private static final byte LITERAL_MASK = 0x02; 123 private static final byte EXPLICIT_MASK = 0x04; 124 private static final byte OPTIONAL_MASK = 0x08; 125 126 // These are tokens for separator characters. 127 128 private static final char TT_COMMA = ','; 129 private static final char TT_EQUALS = '='; 130 private static final char TT_FIELD = '#'; 131 private static final char TT_ESCAPE = '\\'; 132 133 // This token is for checking version number 134 // attribute assignment. 135 136 private static final char TT_PERIOD = '.'; 137 138 // Radix64 code characters. 139 140 private static final char UPPER_START_CODE = 'A'; 141 private static final char UPPER_END_CODE = 'Z'; 142 private static final char LOWER_START_CODE = 'a'; 143 private static final char LOWER_END_CODE = 'z'; 144 private static final char NUMBER_START_CODE = '0'; 145 private static final char NUMBER_END_CODE = '9'; 146 private static final char EXTRA_CODE1 = '+'; 147 private static final char EXTRA_CODE2 = '/'; 148 private static final char PAD_CODE = '='; 149 private static final char LENGTH_SEPERATOR = ':'; 150 151 // The SLP service type of this template. 152 153 private ServiceType serviceType; 154 155 // The template's language locale. 156 157 private Locale locale; 158 159 // The template's version. 160 161 private String version; 162 163 // The template's URL syntax. 164 165 private String URLSyntax; 166 167 // The template's description. 168 169 private String description; 170 171 // The attribute descriptors. 172 173 private Hashtable attributeDescriptors = new Hashtable(); 174 175 // 176 // Constructors. 177 AttributeVerifier()178 AttributeVerifier() { 179 180 } 181 182 // Initialize the attribute verifier with a reader. Subclasses or clients 183 // pass in a Reader on the template that is used for parsing. This 184 // method is used when the template includes the template attributes 185 // and URL rules. 186 initialize(Reader r)187 void initialize(Reader r) throws ServiceLocationException { 188 189 // Use a StreamTokenizer to parse. 190 191 StreamTokenizer tk = new StreamTokenizer(r); 192 193 // Initialize tokenizer for parsing main. 194 195 initFieldChar(tk); 196 197 // Now parse the attribute template, including template attributes. 198 199 parseTemplate(tk); 200 } 201 202 // Initialize with this method when no template attributes are involved. 203 initializeAttributesOnly(Reader r)204 void initializeAttributesOnly(Reader r) 205 throws ServiceLocationException { 206 207 // Use a StreamTokenizer to parse. 208 209 StreamTokenizer tk = new StreamTokenizer(r); 210 211 // Initialize tokenizer for parsing main. 212 213 initFieldChar(tk); 214 215 // Now parse the attribute templates, but no template attributes. 216 217 parseAttributes(tk); 218 } 219 220 // 221 // ServiceLocationAttributeVerifier interface implementation. 222 // 223 224 /** 225 * Returns the SLP service type for which this is the verifier. 226 * 227 * @return The SLP service type name. 228 */ 229 getServiceType()230 public ServiceType getServiceType() { 231 232 return serviceType; 233 } 234 235 /** 236 * Returns the SLP language locale of this is the verifier. 237 * 238 * @return The SLP language locale. 239 */ 240 getLocale()241 public Locale getLocale() { 242 243 return locale; 244 } 245 246 /** 247 * Returns the SLP version of this is the verifier. 248 * 249 * @return The SLP version. 250 */ 251 getVersion()252 public String getVersion() { 253 254 return version; 255 } 256 257 /** 258 * Returns the SLP URL syntax of this is the verifier. 259 * 260 * @return The SLP URL syntax. 261 */ 262 getURLSyntax()263 public String getURLSyntax() { 264 265 return URLSyntax; 266 } 267 268 /** 269 * Returns the SLP description of this is the verifier. 270 * 271 * @return The SLP description. 272 */ 273 getDescription()274 public String getDescription() { 275 276 return description; 277 } 278 279 /** 280 * Returns the ServiceLocationAttributeDescriptor object for the 281 * attribute having the named id. IF no such attribute exists in the 282 * template, returns null. This method is primarily for GUI tools to 283 * display attribute information. Programmatic verification of attributes 284 * should use the verifyAttribute() method. 285 * 286 * @param attrId Id of attribute to return. 287 * @return The ServiceLocationAttributeDescriptor object corresponding 288 * to the parameter, or null if none. 289 */ 290 291 public ServiceLocationAttributeDescriptor getAttributeDescriptor(String attrId)292 getAttributeDescriptor(String attrId) { 293 294 return 295 (ServiceLocationAttributeDescriptor) 296 attributeDescriptors.get(attrId.toLowerCase()); 297 298 } 299 300 /** 301 * Returns an Enumeration of 302 * ServiceLocationAttributeDescriptors for the template. This method 303 * is primarily for GUI tools to display attribute information. 304 * Programmatic verification of attributes should use the 305 * verifyAttribute() method. Note that small memory implementations 306 * may want to implement the Enumeration so that attributes are 307 * parsed on demand rather than at creation time. 308 * 309 * @return A Dictionary with attribute id's as the keys and 310 * ServiceLocationAttributeDescriptor objects for the 311 * attributes as the values. 312 */ 313 getAttributeDescriptors()314 public Enumeration getAttributeDescriptors() { 315 316 return ((Hashtable)attributeDescriptors.clone()).elements(); 317 318 } 319 320 /** 321 * Verify that the attribute parameter is a valid SLP attribute. 322 * 323 * @param attribute The ServiceLocationAttribute to be verified. 324 */ 325 verifyAttribute(ServiceLocationAttribute attribute)326 public void verifyAttribute(ServiceLocationAttribute attribute) 327 throws ServiceLocationException { 328 329 String id = attribute.getId().toLowerCase(); 330 ServiceLocationAttributeDescriptor des = 331 (ServiceLocationAttributeDescriptor)attributeDescriptors.get(id); 332 333 if (des == null) { 334 335 throw 336 new ServiceLocationException( 337 ServiceLocationException.PARSE_ERROR, 338 "template_no_attribute", 339 new Object[] { id }); 340 } 341 342 343 String type = des.getValueType(); 344 Vector vals = attribute.getValues(); 345 346 // If keyword, check that no values were specified. 347 348 if (des.getIsKeyword()) { 349 350 if (vals != null) { 351 throw 352 new ServiceLocationException( 353 ServiceLocationException.PARSE_ERROR, 354 "template_not_null", 355 new Object[] { id }); 356 } 357 } else { 358 359 int i, n; 360 361 // Check that a values vector exists, and, if the attribute is 362 // not multivalued, only one element is in it. 363 364 if (vals == null) { 365 throw 366 new ServiceLocationException( 367 ServiceLocationException.PARSE_ERROR, 368 "template_null", 369 new Object[] { id }); 370 371 } 372 373 n = vals.size(); 374 375 if (n > 1 && !des.getIsMultivalued()) { 376 throw 377 new ServiceLocationException( 378 ServiceLocationException.PARSE_ERROR, 379 "template_not_multi", 380 new Object[] { id }); 381 } 382 383 // Get allowed values. 384 385 Vector av = null; 386 Enumeration en = des.getAllowedValues(); 387 388 if (en.hasMoreElements()) { 389 av = new Vector(); 390 391 while (en.hasMoreElements()) { 392 Object v = en.nextElement(); 393 394 // Lower case if string, convert to Opaque if byte array. 395 396 if (type.equals(JAVA_STRING_TYPE)) { 397 v = ((String)v).toLowerCase(); 398 399 } else if (type.equals(JAVA_OPAQUE_TYPE)) { 400 v = new Opaque((byte[])v); 401 402 } 403 av.addElement(v); 404 405 } 406 } 407 408 // Check that the types of the values vector match the attribute 409 // type. Also, if any allowed values, that attribute values 410 // match. 411 412 String attTypeName = des.getValueType(); 413 414 for (i = 0; i < n; i++) { 415 Object val = vals.elementAt(i); 416 417 String typeName = val.getClass().getName(); 418 419 if (!typeName.equals(attTypeName)) { 420 throw 421 new ServiceLocationException( 422 ServiceLocationException.PARSE_ERROR, 423 "template_type_mismatch", 424 new Object[] { id, typeName, attTypeName }); 425 426 } 427 428 // Convert value for comparison, if necessary. 429 430 if (type.equals(JAVA_STRING_TYPE)) { 431 val = ((String)val).toLowerCase(); 432 433 } else if (type.equals(JAVA_OPAQUE_TYPE)) { 434 val = new Opaque((byte[])val); 435 436 } 437 438 if (av != null && !av.contains(val)) { 439 throw 440 new ServiceLocationException( 441 ServiceLocationException.PARSE_ERROR, 442 "template_not_allowed_value", 443 new Object[] {id, val}); 444 445 } 446 } 447 448 } 449 450 // No way to verify `X' because that's a search property. We 451 // must verify `O' in the context of an attribute set. 452 } 453 454 /** 455 * Verify that the set of registration attributes matches the 456 * required attributes for the service. 457 * 458 * @param attributeVector A Vector of ServiceLocationAttribute objects 459 * for the registration. 460 * @exception ServiceLocationException Thrown if the 461 * attribute set is not valid. The message contains information 462 * on the attribute name and problem. 463 */ 464 verifyRegistration(Vector attributeVector)465 public void verifyRegistration(Vector attributeVector) 466 throws ServiceLocationException { 467 468 Assert.nonNullParameter(attributeVector, "attributeVector"); 469 470 471 if (attributeVector.size() <= 0) { 472 473 // Check whether any attributes are required. If so, then 474 // there's an error. 475 476 Enumeration en = attributeDescriptors.elements(); 477 478 while (en.hasMoreElements()) { 479 ServiceLocationAttributeDescriptor attDesc = 480 (ServiceLocationAttributeDescriptor)en.nextElement(); 481 482 if (!attDesc.getIsOptional()) { 483 484 throw 485 new ServiceLocationException( 486 ServiceLocationException.PARSE_ERROR, 487 "template_missing_required", 488 new Object[] { attDesc.getId() }); 489 } 490 } 491 } else { 492 493 // Construct a hashtable of incoming objects, verifying them 494 // while doing so. 495 496 int i, n = attributeVector.size(); 497 Hashtable incoming = new Hashtable(); 498 499 for (i = 0; i < n; i++) { 500 ServiceLocationAttribute attribute = 501 (ServiceLocationAttribute)attributeVector.elementAt(i); 502 String id = attribute.getId().toLowerCase(); 503 504 // If we already have it, signal a duplicate. 505 506 if (incoming.get(id) != null) { 507 throw 508 new ServiceLocationException( 509 ServiceLocationException.PARSE_ERROR, 510 "template_dup", 511 new Object[] { attribute.getId() }); 512 513 } 514 515 verifyAttribute(attribute); 516 517 incoming.put(id, attribute); 518 } 519 520 // Now check that all required attributes are present. 521 522 Enumeration en = attributeDescriptors.elements(); 523 524 while (en.hasMoreElements()) { 525 ServiceLocationAttributeDescriptor attDesc = 526 (ServiceLocationAttributeDescriptor)en.nextElement(); 527 String attrId = attDesc.getId(); 528 529 if (!attDesc.getIsOptional() && 530 incoming.get(attrId.toLowerCase()) == null) { 531 532 throw 533 new ServiceLocationException( 534 ServiceLocationException.PARSE_ERROR, 535 "template_missing_required", 536 new Object[] { attrId }); 537 } 538 } 539 } 540 541 } 542 543 // 544 // Private implementation. This is the template attribute parser. 545 // 546 547 // 548 // Tokenizer initializers. 549 550 // Base initialization. Resets syntax tables, sets up EOL parsing, 551 // and makes word case significant. 552 initForBase(StreamTokenizer tk)553 private void initForBase(StreamTokenizer tk) { 554 555 // Each part of an attribute production must specify which 556 // characters belong to words. 557 558 tk.resetSyntax(); 559 560 // Note that we have to make EOL be whitespace even if significant 561 // because otherwise the line number won't be correctly incremented. 562 563 tk.whitespaceChars((int)'\n', (int)'\n'); 564 565 // Don't lower case tokens. 566 567 tk.lowerCaseMode(false); 568 } 569 570 // Initialize those token characters that appear in all 571 // productions. 572 initCommonToken(StreamTokenizer tk)573 private void initCommonToken(StreamTokenizer tk) { 574 575 // These characters are recognized as parts of tokens. 576 577 tk.wordChars((int)'A', (int)'Z'); 578 tk.wordChars((int)'a', (int)'z'); 579 tk.wordChars((int)'0', (int)'9'); 580 tk.wordChars((int)'&', (int)'&'); 581 tk.wordChars((int)'*', (int)'*'); 582 tk.wordChars((int)':', (int)':'); 583 tk.wordChars((int)'-', (int)'-'); 584 tk.wordChars((int)'_', (int)'_'); 585 tk.wordChars((int)'$', (int)'$'); 586 tk.wordChars((int)'+', (int)'+'); 587 tk.wordChars((int)'@', (int)'@'); 588 tk.wordChars((int)'.', (int)'.'); 589 tk.wordChars((int)'|', (int)'|'); 590 tk.wordChars((int)'<', (int)'<'); 591 tk.wordChars((int)'>', (int)'>'); 592 tk.wordChars((int)'~', (int)'~'); 593 594 } 595 596 // Initialize tokenizer for parsing attribute name, 597 // attribute type and flags, 598 // and for boolean initializer lists. 599 initIdChar(StreamTokenizer tk)600 private void initIdChar(StreamTokenizer tk) { 601 602 initForBase(tk); 603 initCommonToken(tk); 604 605 // Need backslash for escaping. 606 607 tk.wordChars((int)'\\', (int)'\\'); 608 609 // Attribute id, Type, flags, and boolean initialzers 610 // all ignore white space. 611 612 tk.whitespaceChars((int)' ', (int)' '); 613 tk.whitespaceChars((int)'\t', (int)'\t'); 614 615 // Attribute part won't view newline as being significant. 616 617 tk.eolIsSignificant(false); 618 619 // Case is not folded. 620 621 tk.lowerCaseMode(false); 622 } 623 624 // Initialize tokenizer for parsing service type name. 625 // need to restrict characters. 626 initSchemeIdChar(StreamTokenizer tk)627 private void initSchemeIdChar(StreamTokenizer tk) { 628 629 initForBase(tk); 630 631 tk.wordChars((int)'A', (int)'Z'); 632 tk.wordChars((int)'a', (int)'z'); 633 tk.wordChars((int)'0', (int)'9'); 634 tk.wordChars((int)'-', (int)'-'); 635 tk.wordChars((int)'+', (int)'+'); 636 tk.wordChars((int)'.', (int)'.'); // allows naming authority. 637 tk.wordChars((int)':', (int)':'); // for abstract and concrete type. 638 639 // Scheme name, type, flags, and boolean initialzers 640 // all ignore white space. 641 642 tk.whitespaceChars((int)' ', (int)' '); 643 tk.whitespaceChars((int)'\t', (int)'\t'); 644 645 // Scheme part won't view newline as being significant. 646 647 tk.eolIsSignificant(false); 648 649 // Case is not folded. 650 651 tk.lowerCaseMode(false); 652 653 } 654 655 // Initialize tokenizer for string list parsing. 656 // Everything except '#' and ',' is recognized. 657 // Note that whitespace is significant, but 658 // EOL is ignored. 659 initStringItemChar(StreamTokenizer tk)660 private void initStringItemChar(StreamTokenizer tk) { 661 662 initForBase(tk); 663 664 tk.wordChars((int)'\t', (int)'\t'); 665 tk.wordChars((int)' ', (int)'"'); 666 // '#' goes here 667 tk.wordChars((int)'$', (int)'+'); 668 // ',' goes here 669 tk.wordChars((int)'-', (int)'/'); 670 tk.wordChars((int)'0', (int)'9'); 671 tk.wordChars((int)':', (int)':'); 672 // ';' goes here 673 tk.wordChars((int)'<', (int)'@'); 674 tk.wordChars((int)'A', (int)'Z'); 675 tk.wordChars((int)'[', (int)'`'); 676 tk.wordChars((int)'a', (int)'z'); 677 tk.wordChars((int)'{', (int)'~'); 678 679 // '%' is also reserved, but it is postprocessed 680 // after the string is collected. 681 682 // Parse by lines to check when we've reached the end of the list. 683 684 tk.whitespaceChars((int)'\r', (int)'\r'); 685 tk.whitespaceChars((int)'\n', (int)'\n'); 686 tk.eolIsSignificant(true); 687 688 } 689 690 // Initialize tokenizer for integer list parsing. 691 initIntItemChar(StreamTokenizer tk)692 private void initIntItemChar(StreamTokenizer tk) { 693 694 initForBase(tk); 695 696 tk.wordChars((int)'0', (int)'9'); 697 tk.wordChars((int)'-', (int)'-'); 698 tk.wordChars((int)'+', (int)'+'); 699 700 // Integer value list parsing ignores white space. 701 702 tk.whitespaceChars((int)' ', (int)' '); 703 tk.whitespaceChars((int)'\t', (int)'\t'); 704 705 // Parse by lines so we can find the end. 706 707 tk.whitespaceChars((int)'\r', (int)'\r'); 708 tk.whitespaceChars((int)'\n', (int)'\n'); 709 tk.eolIsSignificant(true); 710 711 } 712 713 // Boolean lists have same item syntax as scheme char. 714 715 // Initialize main production parsing. The only 716 // significant token character is <NL> because 717 // parsing is done on a line-oriented basis. 718 initFieldChar(StreamTokenizer tk)719 private void initFieldChar(StreamTokenizer tk) { 720 721 initForBase(tk); 722 723 tk.wordChars((int)'\t', (int)'\t'); 724 tk.wordChars((int)' ', (int)'/'); 725 tk.wordChars((int)'0', (int)'9'); 726 tk.wordChars((int)':', (int)'@'); 727 tk.wordChars((int)'A', (int)'Z'); 728 tk.wordChars((int)'[', (int)'`'); 729 tk.wordChars((int)'a', (int)'z'); 730 tk.wordChars((int)'{', (int)'~'); 731 732 tk.whitespaceChars((int)'\r', (int)'\r'); 733 tk.whitespaceChars((int)'\n', (int)'\n'); 734 tk.eolIsSignificant(true); 735 } 736 737 // 738 // Parsing methods. 739 // 740 741 // Parse a template from the tokenizer. 742 parseTemplate(StreamTokenizer tk)743 private void parseTemplate(StreamTokenizer tk) 744 throws ServiceLocationException { 745 746 // First parse past the template attributes. 747 748 parseTemplateAttributes(tk); 749 750 // Finally, parse the attributes. 751 752 parseAttributes(tk); 753 754 } 755 756 // Parse the template attributes from the tokenizer. 757 parseTemplateAttributes(StreamTokenizer tk)758 private void parseTemplateAttributes(StreamTokenizer tk) 759 throws ServiceLocationException { 760 761 int found = 0; 762 763 // Parse each of the template attributes. Note that we are parsing 764 // the attribute value assignments, not definitions. 765 766 try { 767 768 do { 769 770 found = found | parseTemplateAttribute(tk, found); 771 772 } while (found != TEMPLATE_FOUND); 773 774 } catch (IOException ex) { 775 776 throw 777 new ServiceLocationException( 778 ServiceLocationException.INTERNAL_SYSTEM_ERROR, 779 "template_io_error", 780 new Object[] {Integer.toString(tk.lineno())}); 781 782 } 783 } 784 785 // Parse a template attribute. 786 parseTemplateAttribute(StreamTokenizer tk, int found)787 private int parseTemplateAttribute(StreamTokenizer tk, int found) 788 throws ServiceLocationException, IOException { 789 790 // Get line including id and equals. 791 792 int tt = tk.nextToken(); 793 794 if (tt != StreamTokenizer.TT_WORD) { 795 796 throw 797 new ServiceLocationException( 798 ServiceLocationException.PARSE_ERROR, 799 "template_assign_error", 800 new Object[] {Integer.toString(tk.lineno())}); 801 } 802 803 // Get tokenizer for id and potential value line. 804 805 StringReader rdr = new StringReader(tk.sval); 806 StreamTokenizer stk = new StreamTokenizer(rdr); 807 808 initIdChar(stk); 809 810 // Make sure newline is there. 811 812 if ((tt = tk.nextToken()) == StreamTokenizer.TT_EOF) { 813 814 throw 815 new ServiceLocationException( 816 ServiceLocationException.PARSE_ERROR, 817 "template_end_error", 818 new Object[] {Integer.toString(tk.lineno())}); 819 820 } 821 822 if (tt != StreamTokenizer.TT_EOL) { 823 824 throw 825 new ServiceLocationException( 826 ServiceLocationException.PARSE_ERROR, 827 "template_unk_token", 828 new Object[] {Integer.toString(tk.lineno())}); 829 830 } 831 832 833 // Parse off id. 834 835 if ((tt = stk.nextToken()) != StreamTokenizer.TT_WORD) { 836 837 throw 838 new ServiceLocationException( 839 ServiceLocationException.PARSE_ERROR, 840 "template_missing_id", 841 new Object[] {Integer.toString(tk.lineno())}); 842 } 843 844 String id = stk.sval; 845 boolean duplicate = false; 846 int mask = 0; 847 848 // Check for the equals. 849 850 if ((tt = stk.nextToken()) != TT_EQUALS) { 851 852 throw 853 new ServiceLocationException( 854 ServiceLocationException.PARSE_ERROR, 855 "template_missing_eq ", 856 new Object[] {Integer.toString(tk.lineno())}); 857 858 } 859 860 // Depending on the id, parse the rest. 861 862 if (id.equalsIgnoreCase(SLPTemplateRegistry.SERVICE_ATTR_ID)) { 863 864 if ((found & SERVICE_MASK) == 0) { 865 866 // Just need to parse off the service type. 867 868 if ((tt = stk.nextToken()) != StreamTokenizer.TT_WORD) { 869 throw 870 new ServiceLocationException( 871 ServiceLocationException.PARSE_ERROR, 872 "template_srv_type_err", 873 new Object[] {Integer.toString(tk.lineno())}); 874 } 875 876 // Check for characters which are not alphanumerics, + and -. 877 // Service type names are more heavily restricted. 878 879 StreamTokenizer sttk = 880 new StreamTokenizer(new StringReader(stk.sval)); 881 882 initSchemeIdChar(sttk); 883 884 if (sttk.nextToken() != StreamTokenizer.TT_WORD || 885 !stk.sval.equals(sttk.sval)) { 886 throw 887 new ServiceLocationException( 888 ServiceLocationException.PARSE_ERROR, 889 "template_srv_type_err", 890 new Object[] {Integer.toString(tk.lineno())}); 891 892 } 893 894 // Need to prefix with "serivce:". 895 896 String typeName = sttk.sval; 897 898 if (!typeName.startsWith(Defaults.SERVICE_PREFIX+":")) { 899 typeName = Defaults.SERVICE_PREFIX+":"+typeName; 900 901 } 902 903 // Set service type instance variable. 904 905 serviceType = new ServiceType(typeName); 906 907 // Check for extra stuff. 908 909 if ((tt = stk.nextToken()) != StreamTokenizer.TT_EOF) { 910 throw 911 new ServiceLocationException( 912 ServiceLocationException.PARSE_ERROR, 913 "template_srv_type_err", 914 new Object[] {Integer.toString(tk.lineno())}); 915 } 916 917 mask = SERVICE_MASK; 918 } else { 919 920 duplicate = true; 921 } 922 } else if (id.equalsIgnoreCase(SLPTemplateRegistry.VERSION_ATTR_ID)) { 923 924 if ((found & VERSION_MASK) == 0) { 925 926 // Just need to parse off the version number. 927 928 if ((tt = stk.nextToken()) != StreamTokenizer.TT_WORD) { 929 throw 930 new ServiceLocationException( 931 ServiceLocationException.PARSE_ERROR, 932 "template_vers_err", 933 new Object[] {Integer.toString(tk.lineno())}); 934 } 935 936 // Make sure it's a valid version number. 937 938 String version = stk.sval; 939 940 if (version.indexOf(TT_PERIOD) == -1) { 941 942 throw 943 new ServiceLocationException( 944 ServiceLocationException.PARSE_ERROR, 945 "template_vers_mssing", 946 new Object[] {Integer.toString(tk.lineno())}); 947 948 } 949 950 try { 951 952 new Float(version); 953 } catch (NumberFormatException ex) { 954 955 throw 956 new ServiceLocationException( 957 ServiceLocationException.PARSE_ERROR, 958 "template_vers_err", 959 new Object[] {Integer.toString(tk.lineno())}); 960 961 } 962 963 this.version = version; 964 965 // Check for extra stuff. 966 967 if ((tt = stk.nextToken()) != StreamTokenizer.TT_EOF) { 968 throw 969 new ServiceLocationException( 970 ServiceLocationException.PARSE_ERROR, 971 "template_vers_err", 972 new Object[] {Integer.toString(tk.lineno())}); 973 } 974 975 mask = VERSION_MASK; 976 } else { 977 978 duplicate = true; 979 } 980 } else if (id.equalsIgnoreCase( 981 SLPTemplateRegistry.DESCRIPTION_ATTR_ID)) { 982 983 // Make sure there is nothing else on that line. 984 985 if (stk.nextToken() != StreamTokenizer.TT_EOF) { 986 987 throw 988 new ServiceLocationException( 989 ServiceLocationException.PARSE_ERROR, 990 "template_attr_syntax", 991 new Object[] {Integer.toString(tk.lineno())}); 992 } 993 994 if ((found & DESCRIPTION_MASK) == 0) { 995 996 // Need to continue parsing help text until we reach a blank 997 // line. 998 999 String helpText = ""; 1000 1001 do { 1002 int ptt = tt; 1003 tt = tk.nextToken(); 1004 1005 if (tt == StreamTokenizer.TT_WORD) { 1006 1007 helpText = helpText + tk.sval + "\n"; 1008 1009 } else if (tt == StreamTokenizer.TT_EOL) { 1010 1011 // If previous token was end of line, quit. 1012 1013 if (ptt == StreamTokenizer.TT_EOL) { 1014 1015 // Store any text first. 1016 1017 if (helpText.length() > 0) { 1018 description = helpText; 1019 1020 } 1021 1022 tk.pushBack(); // so same as above 1023 1024 break; 1025 } 1026 } else if (tt == StreamTokenizer.TT_EOF) { 1027 throw 1028 new ServiceLocationException( 1029 ServiceLocationException.PARSE_ERROR, 1030 "template_end_error", 1031 new Object[] {Integer.toString(tk.lineno())}); 1032 1033 } else { 1034 1035 throw 1036 new ServiceLocationException( 1037 ServiceLocationException.PARSE_ERROR, 1038 "template_unk_token", 1039 new Object[] {Integer.toString(tk.lineno())}); 1040 1041 } 1042 1043 } while (true); 1044 1045 mask = DESCRIPTION_MASK; 1046 } else { 1047 1048 duplicate = true; 1049 } 1050 } else if (id.equalsIgnoreCase( 1051 SLPTemplateRegistry.SERVICE_URL_ATTR_ID)) { 1052 1053 if ((found & URL_PATH_RULES_MASK) == 0) { 1054 1055 String serviceURLGrammer = ""; 1056 1057 // Pull everything out of the rdr StringReader until empty. 1058 1059 int ic; 1060 1061 while ((ic = rdr.read()) != -1) { 1062 serviceURLGrammer += (char)ic; 1063 1064 } 1065 1066 serviceURLGrammer += "\n"; 1067 1068 // Need to continue parsing service URL syntax until we 1069 // reach a blank line. 1070 1071 tt = StreamTokenizer.TT_EOL; 1072 1073 do { 1074 int ptt = tt; 1075 tt = tk.nextToken(); 1076 1077 if (tt == StreamTokenizer.TT_WORD) { 1078 1079 serviceURLGrammer = serviceURLGrammer + tk.sval + "\n"; 1080 1081 } else if (tt == StreamTokenizer.TT_EOL) { 1082 1083 // If previous token was end of line, quit. 1084 1085 if (ptt == StreamTokenizer.TT_EOL) { 1086 1087 // Store any text first. 1088 1089 if (serviceURLGrammer.length() > 0) { 1090 URLSyntax = serviceURLGrammer; 1091 1092 } 1093 1094 tk.pushBack(); // so same as above. 1095 1096 break; 1097 } 1098 } else if (tt == StreamTokenizer.TT_EOF) { 1099 throw 1100 new ServiceLocationException( 1101 ServiceLocationException.PARSE_ERROR, 1102 "template_end_error", 1103 new Object[] {Integer.toString(tk.lineno())}); 1104 1105 } else { 1106 1107 throw 1108 new ServiceLocationException( 1109 ServiceLocationException.PARSE_ERROR, 1110 "template_unk_token", 1111 new Object[] {Integer.toString(tk.lineno())}); 1112 1113 } 1114 1115 } while (true); 1116 1117 mask = URL_PATH_RULES_MASK; 1118 } else { 1119 1120 duplicate = true; 1121 } 1122 } else { 1123 1124 throw 1125 new ServiceLocationException( 1126 ServiceLocationException.PARSE_ERROR, 1127 "template_nontattribute_err", 1128 new Object[] {Integer.toString(tk.lineno())}); 1129 1130 } 1131 1132 // Throw exception if a duplicate definition was detected. 1133 1134 if (duplicate) { 1135 1136 throw 1137 new ServiceLocationException( 1138 ServiceLocationException.PARSE_ERROR, 1139 "template_dup_def", 1140 new Object[] {Integer.toString(tk.lineno())}); 1141 1142 } 1143 1144 1145 // Make sure the assignment ends with a blank line. 1146 1147 if ((tt = tk.nextToken()) != StreamTokenizer.TT_EOL) { 1148 1149 throw 1150 new ServiceLocationException( 1151 ServiceLocationException.PARSE_ERROR, 1152 "template_attr_syntax", 1153 new Object[] {Integer.toString(tk.lineno())}); 1154 1155 } 1156 1157 return mask; 1158 1159 } 1160 1161 1162 // Parse the attributes from the tokenizer. 1163 parseAttributes(StreamTokenizer tk)1164 private void parseAttributes(StreamTokenizer tk) 1165 throws ServiceLocationException { 1166 1167 try { 1168 1169 do { 1170 1171 // Check if at end of file yet. 1172 1173 int tt = tk.nextToken(); 1174 1175 if (tt == StreamTokenizer.TT_EOF) { 1176 break; 1177 } 1178 1179 // If not, push token back so we can get it next time. 1180 1181 tk.pushBack(); 1182 1183 // Parse off the attribute descriptor. 1184 1185 AttributeDescriptor attDesc = parseAttribute(tk); 1186 1187 // Check whether default values, if any, are correct. 1188 1189 checkDefaultValues(attDesc); 1190 1191 // If the attribute already exists, then throw exception. 1192 // We could arguably replace existing, but it might 1193 // suprise the user. 1194 1195 String attrId = attDesc.getId().toLowerCase(); 1196 1197 if (attributeDescriptors.get(attrId) != null) { 1198 1199 throw 1200 new ServiceLocationException( 1201 ServiceLocationException.PARSE_ERROR, 1202 "template_dup_def", 1203 new Object[] {Integer.toString(tk.lineno())}); 1204 1205 } 1206 1207 // Add the attribute to the descriptor table. 1208 1209 attributeDescriptors.put(attrId, attDesc); 1210 1211 } while (true); 1212 1213 } catch (IOException ex) { 1214 1215 throw 1216 new ServiceLocationException( 1217 ServiceLocationException.INTERNAL_SYSTEM_ERROR, 1218 "template_io_error", 1219 new Object[] {Integer.toString(tk.lineno())}); 1220 } 1221 1222 } 1223 1224 // Parse a single attribute description from the tokenizer. 1225 1226 private AttributeDescriptor parseAttribute(StreamTokenizer tk)1227 parseAttribute(StreamTokenizer tk) throws ServiceLocationException { 1228 1229 AttributeDescriptor attDesc = new AttributeDescriptor(); 1230 int lineno = 0; 1231 1232 try { 1233 1234 // Parse the string for attribute id, type, and flags. 1235 1236 lineno = tk.lineno(); 1237 1238 int tt = tk.nextToken(); 1239 1240 if (tt != StreamTokenizer.TT_WORD) { 1241 throw 1242 new ServiceLocationException( 1243 ServiceLocationException.PARSE_ERROR, 1244 "template_attr_syntax", 1245 new Object[] {Integer.toString(tk.lineno())}); 1246 } 1247 1248 StreamTokenizer stk = 1249 new StreamTokenizer(new StringReader(tk.sval)); 1250 1251 initIdChar(stk); 1252 1253 // Parse the attribute id. 1254 1255 parseId(stk, attDesc, lineno); 1256 1257 // Parse the type and flags. 1258 1259 parseTypeAndFlags(stk, attDesc, lineno); 1260 1261 tt = tk.nextToken(); 1262 1263 if (tt == StreamTokenizer.TT_EOF) { 1264 1265 throw 1266 new ServiceLocationException( 1267 ServiceLocationException.PARSE_ERROR, 1268 "template_end_error", 1269 new Object[] {Integer.toString(tk.lineno())}); 1270 1271 } 1272 1273 if (tt != StreamTokenizer.TT_EOL) { 1274 1275 throw 1276 new ServiceLocationException( 1277 ServiceLocationException.PARSE_ERROR, 1278 "template_unk_token", 1279 new Object[] {Integer.toString(tk.lineno())}); 1280 1281 } 1282 1283 // Parse initial values. 1284 1285 if (!attDesc.getIsKeyword()) { 1286 1287 String tok = ""; 1288 1289 // Read in entire list. 1290 1291 do { 1292 int ptt = tt; 1293 lineno = tk.lineno(); 1294 tt = tk.nextToken(); 1295 1296 if (tt == StreamTokenizer.TT_WORD) { 1297 1298 // Trim line, check for '#', indicating end of list. 1299 1300 String line = tk.sval.trim(); 1301 1302 if (line.charAt(0) == TT_FIELD) { 1303 // it's help text already. 1304 1305 if (tok.length() > 0) { 1306 stk = 1307 new StreamTokenizer(new StringReader(tok)); 1308 parseDefaultValues(stk, attDesc, lineno); 1309 } 1310 1311 tk.pushBack(); 1312 break; 1313 1314 } else { 1315 1316 // Otherwise concatenate onto growing list. 1317 1318 tok = tok + line; 1319 1320 } 1321 1322 } else if (tt == StreamTokenizer.TT_EOL) { 1323 1324 if (ptt == StreamTokenizer.TT_EOL) { 1325 // end of attribute definition. 1326 1327 // Process any accumulated list. 1328 1329 if (tok.length() > 0) { 1330 stk = 1331 new StreamTokenizer(new StringReader(tok)); 1332 parseDefaultValues(stk, attDesc, lineno); 1333 } 1334 1335 return attDesc; 1336 1337 } 1338 } else if (tt == StreamTokenizer.TT_EOF) { 1339 throw 1340 new ServiceLocationException( 1341 ServiceLocationException.PARSE_ERROR, 1342 "template_end_error", 1343 new Object[] {Integer.toString(tk.lineno())}); 1344 1345 } else { 1346 1347 throw 1348 new ServiceLocationException( 1349 ServiceLocationException.PARSE_ERROR, 1350 "template_unk_token", 1351 new Object[] {Integer.toString(tk.lineno())}); 1352 1353 } 1354 1355 } while (true); 1356 1357 } else { 1358 attDesc.setDefaultValues(null); 1359 attDesc.setAllowedValues(null); 1360 1361 // Check for end of definition. 1362 1363 if ((tt = tk.nextToken()) == StreamTokenizer.TT_EOL) { 1364 return attDesc; 1365 1366 } else if (tt == StreamTokenizer.TT_WORD) { 1367 1368 // Check for start of help text. 1369 1370 String line = tk.sval.trim(); 1371 1372 if (line.charAt(0) != TT_FIELD) { 1373 throw 1374 new ServiceLocationException( 1375 ServiceLocationException.PARSE_ERROR, 1376 "template_attr_syntax", 1377 new Object[] {Integer.toString(tk.lineno())}); 1378 1379 } else { 1380 1381 tk.pushBack(); 1382 1383 } 1384 1385 } else if (tt == StreamTokenizer.TT_EOF) { 1386 throw 1387 new ServiceLocationException( 1388 ServiceLocationException.PARSE_ERROR, 1389 "template_end_error", 1390 new Object[] {Integer.toString(tk.lineno())}); 1391 1392 } else { 1393 1394 throw 1395 new ServiceLocationException( 1396 ServiceLocationException.PARSE_ERROR, 1397 "template_unk_token", 1398 new Object[] {Integer.toString(tk.lineno())}); 1399 1400 } 1401 } 1402 1403 1404 // Parse help text. 1405 1406 String helpText = ""; 1407 1408 do { 1409 int ptt = tt; 1410 lineno = tk.lineno(); 1411 tt = tk.nextToken(); 1412 1413 if (tt == StreamTokenizer.TT_WORD) { 1414 1415 // Check for end of help text. 1416 1417 String line = tk.sval.trim(); 1418 1419 if (line.charAt(0) == TT_FIELD) { 1420 1421 // Help text is collected verbatim after '#'. 1422 1423 helpText = 1424 helpText + line.substring(1) + "\n"; 1425 1426 } else { 1427 1428 // We've reached the end of the help text. Store it 1429 // and break out of the loop. 1430 1431 if (helpText.length() > 0) { 1432 attDesc.setDescription(helpText); 1433 } 1434 1435 tk.pushBack(); 1436 break; 1437 1438 } 1439 1440 } else if (tt == StreamTokenizer.TT_EOL || 1441 tt == StreamTokenizer.TT_EOF) { 1442 1443 // If previous token was end of line, quit. 1444 1445 if (ptt == StreamTokenizer.TT_EOL) { 1446 1447 // Store any text first. 1448 1449 if (helpText.length() > 0) { 1450 attDesc.setDescription(helpText); 1451 } 1452 1453 // If this is a keyword attribute, set the allowed 1454 // values list to null. 1455 1456 if (attDesc.getIsKeyword()) { 1457 attDesc.setAllowedValues(null); 1458 } 1459 1460 return attDesc; 1461 1462 } else if (tt == StreamTokenizer.TT_EOF) { 1463 1464 // Error if previous token wasn't EOL. 1465 1466 throw 1467 new ServiceLocationException( 1468 ServiceLocationException.PARSE_ERROR, 1469 "template_end_error", 1470 new Object[] {Integer.toString(tk.lineno())}); 1471 } 1472 1473 } else { 1474 1475 throw 1476 new ServiceLocationException( 1477 ServiceLocationException.PARSE_ERROR, 1478 "template_unk_token", 1479 new Object[] {Integer.toString(tk.lineno())}); 1480 } 1481 1482 } while (true); 1483 1484 // Parse allowed values. 1485 1486 if (!attDesc.getIsKeyword()) { 1487 1488 String tok = ""; 1489 1490 // Read in entire list. 1491 1492 do { 1493 int ptt = tt; 1494 lineno = tk.lineno(); 1495 tt = tk.nextToken(); 1496 1497 if (tt == StreamTokenizer.TT_WORD) { 1498 1499 // Concatenate onto growing list. 1500 1501 tok = tok + tk.sval; 1502 1503 } else if (tt == StreamTokenizer.TT_EOL) { 1504 1505 if (ptt == StreamTokenizer.TT_EOL) { 1506 // end of attribute definition. 1507 1508 // Process any accumulated list. 1509 1510 if (tok.length() > 0) { 1511 stk = 1512 new StreamTokenizer(new StringReader(tok)); 1513 parseAllowedValues(stk, attDesc, lineno); 1514 } 1515 1516 return attDesc; 1517 1518 } 1519 } else if (tt == StreamTokenizer.TT_EOF) { 1520 throw 1521 new ServiceLocationException( 1522 ServiceLocationException.PARSE_ERROR, 1523 "template_end_error", 1524 new Object[] {Integer.toString(tk.lineno())}); 1525 1526 } else { 1527 1528 throw 1529 new ServiceLocationException( 1530 ServiceLocationException.PARSE_ERROR, 1531 "template_unk_token", 1532 new Object[] {Integer.toString(tk.lineno())}); 1533 } 1534 1535 } while (true); 1536 1537 } else { 1538 1539 // Error. Keyword attribute should have ended during help text 1540 // parsing or before. 1541 1542 throw 1543 new ServiceLocationException( 1544 ServiceLocationException.PARSE_ERROR, 1545 "template_attr_syntax", 1546 new Object[] {Integer.toString(tk.lineno())}); 1547 } 1548 1549 } catch (IOException ex) { 1550 1551 throw 1552 new ServiceLocationException( 1553 ServiceLocationException.INTERNAL_SYSTEM_ERROR, 1554 "template_io_error", 1555 new Object[] { 1556 Integer.toString(tk.lineno()), 1557 ex.getMessage()}); 1558 } 1559 1560 } 1561 1562 // Check whether the default values, if any, are correct. 1563 checkDefaultValues(AttributeDescriptor attDesc)1564 private void checkDefaultValues(AttributeDescriptor attDesc) 1565 throws ServiceLocationException { 1566 1567 // Don't bother if it's a keyword attribute, parsing has checked. 1568 1569 if (attDesc.getIsKeyword()) { 1570 return; 1571 } 1572 1573 Enumeration init = attDesc.getDefaultValues(); 1574 Enumeration en = attDesc.getAllowedValues(); 1575 Vector allowed = new Vector(); 1576 String attDescType = attDesc.getValueType(); 1577 1578 // First, collect the allowed values. 1579 1580 while (en.hasMoreElements()) { 1581 Object allval = en.nextElement(); 1582 1583 // Lower case strings and create opaques for comparison 1584 // if type is opaque. 1585 1586 if (attDescType.equals(JAVA_STRING_TYPE)) { 1587 allval = ((String)allval).toLowerCase(); 1588 1589 } else if (attDescType.equals(JAVA_OPAQUE_TYPE)) { 1590 allval = new Opaque((byte[])allval); 1591 1592 } 1593 1594 allowed.addElement(allval); 1595 } 1596 1597 // Now compare the allowed with the initial. 1598 1599 if (allowed.size() > 0) { 1600 1601 // Error if allowed is restricted but no initializers. 1602 1603 if (!init.hasMoreElements()) { 1604 1605 throw 1606 new ServiceLocationException( 1607 ServiceLocationException.PARSE_ERROR, 1608 "template_no_init", 1609 new Object[] {attDesc.getId()}); 1610 1611 } 1612 1613 Object val = null; 1614 1615 // Compare init values with allowed. 1616 1617 while (init.hasMoreElements()) { 1618 Object test = init.nextElement(); 1619 val = test; // for exception.. 1620 1621 if (attDescType.equals(JAVA_STRING_TYPE)) { 1622 test = ((String)test).toLowerCase(); 1623 1624 } else if (attDescType.equals(JAVA_OPAQUE_TYPE)) { 1625 test = new Opaque((byte[])test); 1626 1627 } 1628 1629 if (allowed.indexOf(test) != -1) { 1630 return; // found it! 1631 } 1632 } 1633 // Initializer wasn't found. 1634 1635 throw 1636 new ServiceLocationException( 1637 ServiceLocationException.PARSE_ERROR, 1638 "template_wrong_init", 1639 new Object[] { 1640 val.toString(), attDesc.getId()}); 1641 } 1642 } 1643 1644 // Parse the attribute's id string. 1645 parseId(StreamTokenizer tk, AttributeDescriptor attDesc, int baseLineno)1646 private void parseId(StreamTokenizer tk, 1647 AttributeDescriptor attDesc, 1648 int baseLineno) 1649 throws ServiceLocationException, IOException { 1650 1651 // Parse the attribute's identifier tag. 1652 1653 String id = parseWord(tk, baseLineno); 1654 1655 int tt = tk.nextToken(); 1656 1657 // Parse the seperator. 1658 1659 if (tt != TT_EQUALS) { 1660 throw 1661 new ServiceLocationException( 1662 ServiceLocationException.PARSE_ERROR, 1663 "template_attr_syntax", 1664 new Object[] { 1665 Integer.toString(tk.lineno() + baseLineno)}); 1666 1667 } 1668 1669 // Expand out any escaped ``#''. It won't be handled by 1670 // SLA. 1671 1672 id = unescapeHash(id); 1673 1674 // Expand out character escapes. 1675 1676 id = 1677 ServiceLocationAttribute.unescapeAttributeString(id, true); 1678 1679 1680 attDesc.setId(id); 1681 } 1682 1683 // Parse the attribute's type and flags. 1684 1685 private void parseTypeAndFlags(StreamTokenizer tk, AttributeDescriptor attDesc, int baseLineno)1686 parseTypeAndFlags(StreamTokenizer tk, 1687 AttributeDescriptor attDesc, 1688 int baseLineno) 1689 throws ServiceLocationException, IOException { 1690 1691 int existingFlags = 0; 1692 1693 // Parse the attribute's type. 1694 1695 String type = parseWord(tk, baseLineno); 1696 1697 checkAndAddType(type, attDesc, tk.lineno() + baseLineno); 1698 1699 // Parse the flags. 1700 1701 do { 1702 1703 // Check if any flags are left. 1704 1705 if (tk.nextToken() == StreamTokenizer.TT_EOF) { 1706 break; 1707 1708 } else { 1709 tk.pushBack(); 1710 } 1711 1712 int lineno = tk.lineno(); 1713 1714 // Parse the flag. 1715 1716 String flag = parseWord(tk, baseLineno); 1717 1718 // Error if flags with keyword. 1719 1720 if (attDesc.getIsKeyword()) { 1721 throw 1722 new ServiceLocationException( 1723 ServiceLocationException.PARSE_ERROR, 1724 "template_attr_syntax", 1725 new Object[] { 1726 Integer.toString(tk.lineno() + baseLineno)}); 1727 } 1728 1729 1730 // Check and assign it to the attribute. 1731 1732 existingFlags = 1733 existingFlags | checkAndAddFlag(flag, 1734 existingFlags, 1735 attDesc, 1736 baseLineno + lineno); 1737 1738 } while (true); 1739 } 1740 1741 // Parse the attribute's initial value(s). 1742 parseDefaultValues(StreamTokenizer tk, AttributeDescriptor attDesc, int baseLineno)1743 private void parseDefaultValues(StreamTokenizer tk, 1744 AttributeDescriptor attDesc, 1745 int baseLineno) 1746 throws ServiceLocationException, IOException { 1747 1748 // First get the vector of initial values. 1749 1750 Vector vals = parseValueList(tk, attDesc, baseLineno); 1751 1752 // Check whether it works for this attribute. Type 1753 // checking will be done by value list parsing. 1754 1755 if (!attDesc.getIsMultivalued() && vals.size() > 1) { 1756 throw 1757 new ServiceLocationException( 1758 ServiceLocationException.PARSE_ERROR, 1759 "template_attr_syntax", 1760 new Object[] { 1761 Integer.toString(tk.lineno() + baseLineno)}); 1762 } 1763 1764 attDesc.setDefaultValues(vals); 1765 } 1766 1767 // Parse the attribute's allowed values. 1768 1769 private void parseAllowedValues(StreamTokenizer tk, AttributeDescriptor attDesc, int baseLineno)1770 parseAllowedValues(StreamTokenizer tk, 1771 AttributeDescriptor attDesc, 1772 int baseLineno) 1773 throws ServiceLocationException, IOException { 1774 1775 // First get the vector of all allowed values. 1776 1777 Vector vals = parseValueList(tk, attDesc, baseLineno); 1778 1779 // Now set the allowed value vector. 1780 1781 attDesc.setAllowedValues(vals); 1782 } 1783 1784 // Parse a value list. 1785 parseValueList(StreamTokenizer stk, AttributeDescriptor attDesc, int baseLineno)1786 private Vector parseValueList(StreamTokenizer stk, 1787 AttributeDescriptor attDesc, 1788 int baseLineno) 1789 throws ServiceLocationException, IOException { 1790 1791 Vector req = new Vector(); 1792 1793 // Set up the tokenizer according to the type of the 1794 // attribute. 1795 1796 String type = attDesc.getValueType(); 1797 1798 if (type.equals(JAVA_STRING_TYPE) || type.equals(JAVA_OPAQUE_TYPE)) { 1799 initStringItemChar(stk); 1800 } else if (type.equals(JAVA_INTEGER_TYPE)) { 1801 initIntItemChar(stk); 1802 } else if (type.equals(JAVA_BOOLEAN_TYPE)) { 1803 initIdChar(stk); 1804 } 1805 1806 // Parse through a potentially multivalued value list. 1807 1808 boolean wordRequired = true; // true when a word is required, 1809 // false when a comma required. 1810 boolean syntaxError = false; 1811 String reqTok = ""; 1812 int lineno = 0; 1813 1814 do { 1815 int tt = stk.nextToken(); 1816 lineno = stk.lineno() + baseLineno; 1817 1818 if (tt == StreamTokenizer.TT_WORD) { 1819 1820 // If a word isn't required, then the case is 1821 // "token token" and is an error. 1822 1823 if (!wordRequired) { 1824 syntaxError = true; 1825 } 1826 1827 reqTok = stk.sval.trim(); 1828 1829 // Convert the value to the proper object. 1830 1831 Object reqVal = convertValue(type, reqTok, baseLineno); 1832 req.addElement(reqVal); 1833 1834 wordRequired = false; 1835 1836 } else if (tt == StreamTokenizer.TT_EOF) { 1837 1838 // If a word is required, then list ends with 1839 // a comma, so error. 1840 1841 if (wordRequired) { 1842 syntaxError = true; 1843 } 1844 1845 break; 1846 1847 } else if (tt == TT_COMMA) { 1848 1849 // If a word is required, then error. The case is ",,". 1850 1851 if (wordRequired) { 1852 syntaxError = true; 1853 break; 1854 } 1855 1856 // Otherwise, the next token must be a word. 1857 1858 wordRequired = true; 1859 1860 } else { 1861 1862 // No other tokens are allowed. 1863 1864 syntaxError = true; 1865 break; 1866 } 1867 1868 } while (true); 1869 1870 if (syntaxError) { 1871 1872 throw 1873 new ServiceLocationException( 1874 ServiceLocationException.PARSE_ERROR, 1875 "template_attr_syntax", 1876 new Object[] {Integer.toString(lineno)}); 1877 } 1878 1879 return req; 1880 1881 } 1882 1883 // Check the type and add it to the attribute descriptor. 1884 checkAndAddType(String type, AttributeDescriptor attDesc, int lineno)1885 private void checkAndAddType(String type, 1886 AttributeDescriptor attDesc, 1887 int lineno) 1888 throws ServiceLocationException { 1889 1890 // Check token against recognized types. 1891 1892 if (type.equalsIgnoreCase(STRING_TYPE)) { 1893 attDesc.setValueType(JAVA_STRING_TYPE); 1894 1895 } else if (type.equalsIgnoreCase(INTEGER_TYPE)) { 1896 attDesc.setValueType(JAVA_INTEGER_TYPE); 1897 1898 } else if (type.equalsIgnoreCase(BOOLEAN_TYPE)) { 1899 attDesc.setValueType(JAVA_BOOLEAN_TYPE); 1900 1901 } else if (type.equalsIgnoreCase(OPAQUE_TYPE)) { 1902 attDesc.setValueType(JAVA_OPAQUE_TYPE); 1903 1904 } else if (type.equalsIgnoreCase(KEYWORD_TYPE)) { 1905 attDesc.setIsKeyword(true); 1906 1907 } else { 1908 1909 throw 1910 new ServiceLocationException( 1911 ServiceLocationException.PARSE_ERROR, 1912 "template_not_slp_type", 1913 new Object[] {Integer.toString(lineno)}); 1914 } 1915 1916 } 1917 1918 // Check the flag and add it to the attribute descriptor. 1919 checkAndAddFlag(String flag, int matched, AttributeDescriptor attDesc, int lineno)1920 private int checkAndAddFlag(String flag, 1921 int matched, 1922 AttributeDescriptor attDesc, 1923 int lineno) 1924 throws ServiceLocationException { 1925 1926 boolean duplicate = false; 1927 1928 // We depend on the attribute descriptor being initialized to 1929 // nothing, i.e. false for all flags and for keyword. 1930 1931 if (flag.equalsIgnoreCase(MULTIPLE_FLAG)) { 1932 1933 if ((matched & MULTIPLE_MASK) != 0) { 1934 duplicate = true; 1935 1936 } else { 1937 1938 // Check for boolean. Booleans may not have 1939 // multiple values. 1940 1941 if (attDesc.getValueType().equals(JAVA_BOOLEAN_TYPE)) { 1942 1943 throw 1944 new ServiceLocationException( 1945 ServiceLocationException.PARSE_ERROR, 1946 "template_boolean_multi", 1947 new Object[] {Integer.toString(lineno)}); 1948 } 1949 1950 attDesc.setIsMultivalued(true); 1951 return MULTIPLE_MASK; 1952 1953 } 1954 1955 } else if (flag.equalsIgnoreCase(LITERAL_FLAG)) { 1956 1957 if ((matched & LITERAL_MASK) != 0) { 1958 duplicate = true; 1959 1960 } else { 1961 attDesc.setIsLiteral(true); 1962 return LITERAL_MASK; 1963 } 1964 1965 } else if (flag.equalsIgnoreCase(EXPLICIT_FLAG)) { 1966 1967 if ((matched & EXPLICIT_MASK) != 0) { 1968 duplicate = true; 1969 1970 } else { 1971 attDesc.setRequiresExplicitMatch(true); 1972 return EXPLICIT_MASK; 1973 } 1974 1975 } else if (flag.equalsIgnoreCase(OPTIONAL_FLAG)) { 1976 1977 if ((matched & OPTIONAL_MASK) != 0) { 1978 duplicate = true; 1979 1980 } else { 1981 attDesc.setIsOptional(true); 1982 return OPTIONAL_MASK; 1983 } 1984 1985 } else { 1986 1987 throw 1988 new ServiceLocationException( 1989 ServiceLocationException.PARSE_ERROR, 1990 "template_invalid_attr_flag", 1991 new Object[] {Integer.toString(lineno)}); 1992 } 1993 1994 1995 if (duplicate) { 1996 throw 1997 new ServiceLocationException( 1998 ServiceLocationException.PARSE_ERROR, 1999 "template_dup_attr_flag", 2000 new Object[] {Integer.toString(lineno)}); 2001 } 2002 2003 return 0; // never happens. 2004 } 2005 2006 // Parse a word out of the tokenizer. The exact characters 2007 // will depend on what the syntax tables have been set to. 2008 parseWord(StreamTokenizer tk, int baseLineno)2009 private String parseWord(StreamTokenizer tk, int baseLineno) 2010 throws ServiceLocationException, IOException { 2011 2012 int tt = tk.nextToken(); 2013 2014 if (tt == StreamTokenizer.TT_WORD) { 2015 return (tk.sval); 2016 2017 } else { 2018 2019 String errorToken = ""; 2020 2021 // Report the erroneous characters. 2022 2023 if (tt == StreamTokenizer.TT_NUMBER) { 2024 errorToken = Double.toString(tk.nval); 2025 } else if (tt == StreamTokenizer.TT_EOL) { 2026 errorToken = "<end of line>"; 2027 } else if (tt == StreamTokenizer.TT_EOF) { 2028 errorToken = "<end of file>"; 2029 } else { 2030 errorToken = (new Character((char)tt)).toString(); 2031 } 2032 2033 throw 2034 new ServiceLocationException( 2035 ServiceLocationException.PARSE_ERROR, 2036 "template_invalid_tok", 2037 new Object[] { 2038 Integer.toString(tk.lineno() + baseLineno)}); 2039 2040 } 2041 2042 } 2043 2044 // Convert a value list token to the value. 2045 convertValue(String type, String reqTok, int lineno)2046 private Object convertValue(String type, 2047 String reqTok, 2048 int lineno) 2049 throws ServiceLocationException, 2050 IOException { 2051 2052 Object reqVal = null; 2053 2054 if (type.equals(JAVA_STRING_TYPE)) { 2055 2056 // Expand out any escaped ``#''. It won't be handled by 2057 // SLA. 2058 2059 reqTok = unescapeHash(reqTok); 2060 2061 // Expand out character escapes. 2062 2063 reqVal = 2064 ServiceLocationAttribute.unescapeAttributeString(reqTok, 2065 false); 2066 2067 } else if (type.equals(JAVA_INTEGER_TYPE)) { 2068 2069 try { 2070 2071 reqVal = Integer.valueOf(reqTok); 2072 2073 } catch (NumberFormatException ex) { 2074 2075 throw 2076 new ServiceLocationException( 2077 ServiceLocationException.PARSE_ERROR, 2078 "template_expect_int", 2079 new Object[] { 2080 Integer.toString(lineno), reqTok }); 2081 } 2082 } else if (type.equals(JAVA_BOOLEAN_TYPE)) { 2083 2084 // Boolean.valueOf() doesn't handle this properly. 2085 2086 if (reqTok.equalsIgnoreCase(TRUE_TOKEN)) { 2087 2088 reqVal = new Boolean(true); 2089 2090 } else if (reqTok.equalsIgnoreCase(FALSE_TOKEN)) { 2091 2092 reqVal = new Boolean(false); 2093 2094 } else { 2095 2096 throw 2097 new ServiceLocationException( 2098 ServiceLocationException.PARSE_ERROR, 2099 "template_expect_bool", 2100 new Object[] { 2101 Integer.toString(lineno), reqTok}); 2102 } 2103 } else if (type.equals(JAVA_OPAQUE_TYPE)) { 2104 2105 reqVal = Opaque.unescapeByteArray(reqTok); 2106 2107 } else { 2108 2109 Assert.slpassert(false, 2110 "template_attr_desc", 2111 new Object[0]); 2112 } 2113 2114 return reqVal; 2115 } 2116 2117 // Expand out any escaped hashes. Not handled by SLA. 2118 unescapeHash(String str)2119 private String unescapeHash(String str) { 2120 2121 StringBuffer buf = new StringBuffer(); 2122 int len = ESC_HASH.length(); 2123 int i, j = 0; 2124 2125 for (i = str.indexOf(ESC_HASH, j); 2126 i != -1; 2127 i = str.indexOf(ESC_HASH, j)) { 2128 2129 buf.append(str.substring(j, i)); 2130 buf.append(HASH); 2131 j = i + len; 2132 } 2133 2134 len = str.length(); 2135 2136 if (j < len) { 2137 buf.append(str.substring(j, len)); 2138 2139 } 2140 2141 return buf.toString(); 2142 } 2143 2144 } 2145