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 Float.valueOf(version); 952 } catch (NumberFormatException ex) { 953 954 throw 955 new ServiceLocationException( 956 ServiceLocationException.PARSE_ERROR, 957 "template_vers_err", 958 new Object[] {Integer.toString(tk.lineno())}); 959 960 } 961 962 this.version = version; 963 964 // Check for extra stuff. 965 966 if ((tt = stk.nextToken()) != StreamTokenizer.TT_EOF) { 967 throw 968 new ServiceLocationException( 969 ServiceLocationException.PARSE_ERROR, 970 "template_vers_err", 971 new Object[] {Integer.toString(tk.lineno())}); 972 } 973 974 mask = VERSION_MASK; 975 } else { 976 977 duplicate = true; 978 } 979 } else if (id.equalsIgnoreCase( 980 SLPTemplateRegistry.DESCRIPTION_ATTR_ID)) { 981 982 // Make sure there is nothing else on that line. 983 984 if (stk.nextToken() != StreamTokenizer.TT_EOF) { 985 986 throw 987 new ServiceLocationException( 988 ServiceLocationException.PARSE_ERROR, 989 "template_attr_syntax", 990 new Object[] {Integer.toString(tk.lineno())}); 991 } 992 993 if ((found & DESCRIPTION_MASK) == 0) { 994 995 // Need to continue parsing help text until we reach a blank 996 // line. 997 998 String helpText = ""; 999 1000 do { 1001 int ptt = tt; 1002 tt = tk.nextToken(); 1003 1004 if (tt == StreamTokenizer.TT_WORD) { 1005 1006 helpText = helpText + tk.sval + "\n"; 1007 1008 } else if (tt == StreamTokenizer.TT_EOL) { 1009 1010 // If previous token was end of line, quit. 1011 1012 if (ptt == StreamTokenizer.TT_EOL) { 1013 1014 // Store any text first. 1015 1016 if (helpText.length() > 0) { 1017 description = helpText; 1018 1019 } 1020 1021 tk.pushBack(); // so same as above 1022 1023 break; 1024 } 1025 } else if (tt == StreamTokenizer.TT_EOF) { 1026 throw 1027 new ServiceLocationException( 1028 ServiceLocationException.PARSE_ERROR, 1029 "template_end_error", 1030 new Object[] {Integer.toString(tk.lineno())}); 1031 1032 } else { 1033 1034 throw 1035 new ServiceLocationException( 1036 ServiceLocationException.PARSE_ERROR, 1037 "template_unk_token", 1038 new Object[] {Integer.toString(tk.lineno())}); 1039 1040 } 1041 1042 } while (true); 1043 1044 mask = DESCRIPTION_MASK; 1045 } else { 1046 1047 duplicate = true; 1048 } 1049 } else if (id.equalsIgnoreCase( 1050 SLPTemplateRegistry.SERVICE_URL_ATTR_ID)) { 1051 1052 if ((found & URL_PATH_RULES_MASK) == 0) { 1053 1054 String serviceURLGrammer = ""; 1055 1056 // Pull everything out of the rdr StringReader until empty. 1057 1058 int ic; 1059 1060 while ((ic = rdr.read()) != -1) { 1061 serviceURLGrammer += (char)ic; 1062 1063 } 1064 1065 serviceURLGrammer += "\n"; 1066 1067 // Need to continue parsing service URL syntax until we 1068 // reach a blank line. 1069 1070 tt = StreamTokenizer.TT_EOL; 1071 1072 do { 1073 int ptt = tt; 1074 tt = tk.nextToken(); 1075 1076 if (tt == StreamTokenizer.TT_WORD) { 1077 1078 serviceURLGrammer = serviceURLGrammer + tk.sval + "\n"; 1079 1080 } else if (tt == StreamTokenizer.TT_EOL) { 1081 1082 // If previous token was end of line, quit. 1083 1084 if (ptt == StreamTokenizer.TT_EOL) { 1085 1086 // Store any text first. 1087 1088 if (serviceURLGrammer.length() > 0) { 1089 URLSyntax = serviceURLGrammer; 1090 1091 } 1092 1093 tk.pushBack(); // so same as above. 1094 1095 break; 1096 } 1097 } else if (tt == StreamTokenizer.TT_EOF) { 1098 throw 1099 new ServiceLocationException( 1100 ServiceLocationException.PARSE_ERROR, 1101 "template_end_error", 1102 new Object[] {Integer.toString(tk.lineno())}); 1103 1104 } else { 1105 1106 throw 1107 new ServiceLocationException( 1108 ServiceLocationException.PARSE_ERROR, 1109 "template_unk_token", 1110 new Object[] {Integer.toString(tk.lineno())}); 1111 1112 } 1113 1114 } while (true); 1115 1116 mask = URL_PATH_RULES_MASK; 1117 } else { 1118 1119 duplicate = true; 1120 } 1121 } else { 1122 1123 throw 1124 new ServiceLocationException( 1125 ServiceLocationException.PARSE_ERROR, 1126 "template_nontattribute_err", 1127 new Object[] {Integer.toString(tk.lineno())}); 1128 1129 } 1130 1131 // Throw exception if a duplicate definition was detected. 1132 1133 if (duplicate) { 1134 1135 throw 1136 new ServiceLocationException( 1137 ServiceLocationException.PARSE_ERROR, 1138 "template_dup_def", 1139 new Object[] {Integer.toString(tk.lineno())}); 1140 1141 } 1142 1143 1144 // Make sure the assignment ends with a blank line. 1145 1146 if ((tt = tk.nextToken()) != StreamTokenizer.TT_EOL) { 1147 1148 throw 1149 new ServiceLocationException( 1150 ServiceLocationException.PARSE_ERROR, 1151 "template_attr_syntax", 1152 new Object[] {Integer.toString(tk.lineno())}); 1153 1154 } 1155 1156 return mask; 1157 1158 } 1159 1160 1161 // Parse the attributes from the tokenizer. 1162 parseAttributes(StreamTokenizer tk)1163 private void parseAttributes(StreamTokenizer tk) 1164 throws ServiceLocationException { 1165 1166 try { 1167 1168 do { 1169 1170 // Check if at end of file yet. 1171 1172 int tt = tk.nextToken(); 1173 1174 if (tt == StreamTokenizer.TT_EOF) { 1175 break; 1176 } 1177 1178 // If not, push token back so we can get it next time. 1179 1180 tk.pushBack(); 1181 1182 // Parse off the attribute descriptor. 1183 1184 AttributeDescriptor attDesc = parseAttribute(tk); 1185 1186 // Check whether default values, if any, are correct. 1187 1188 checkDefaultValues(attDesc); 1189 1190 // If the attribute already exists, then throw exception. 1191 // We could arguably replace existing, but it might 1192 // suprise the user. 1193 1194 String attrId = attDesc.getId().toLowerCase(); 1195 1196 if (attributeDescriptors.get(attrId) != null) { 1197 1198 throw 1199 new ServiceLocationException( 1200 ServiceLocationException.PARSE_ERROR, 1201 "template_dup_def", 1202 new Object[] {Integer.toString(tk.lineno())}); 1203 1204 } 1205 1206 // Add the attribute to the descriptor table. 1207 1208 attributeDescriptors.put(attrId, attDesc); 1209 1210 } while (true); 1211 1212 } catch (IOException ex) { 1213 1214 throw 1215 new ServiceLocationException( 1216 ServiceLocationException.INTERNAL_SYSTEM_ERROR, 1217 "template_io_error", 1218 new Object[] {Integer.toString(tk.lineno())}); 1219 } 1220 1221 } 1222 1223 // Parse a single attribute description from the tokenizer. 1224 1225 private AttributeDescriptor parseAttribute(StreamTokenizer tk)1226 parseAttribute(StreamTokenizer tk) throws ServiceLocationException { 1227 1228 AttributeDescriptor attDesc = new AttributeDescriptor(); 1229 int lineno = 0; 1230 1231 try { 1232 1233 // Parse the string for attribute id, type, and flags. 1234 1235 lineno = tk.lineno(); 1236 1237 int tt = tk.nextToken(); 1238 1239 if (tt != StreamTokenizer.TT_WORD) { 1240 throw 1241 new ServiceLocationException( 1242 ServiceLocationException.PARSE_ERROR, 1243 "template_attr_syntax", 1244 new Object[] {Integer.toString(tk.lineno())}); 1245 } 1246 1247 StreamTokenizer stk = 1248 new StreamTokenizer(new StringReader(tk.sval)); 1249 1250 initIdChar(stk); 1251 1252 // Parse the attribute id. 1253 1254 parseId(stk, attDesc, lineno); 1255 1256 // Parse the type and flags. 1257 1258 parseTypeAndFlags(stk, attDesc, lineno); 1259 1260 tt = tk.nextToken(); 1261 1262 if (tt == StreamTokenizer.TT_EOF) { 1263 1264 throw 1265 new ServiceLocationException( 1266 ServiceLocationException.PARSE_ERROR, 1267 "template_end_error", 1268 new Object[] {Integer.toString(tk.lineno())}); 1269 1270 } 1271 1272 if (tt != StreamTokenizer.TT_EOL) { 1273 1274 throw 1275 new ServiceLocationException( 1276 ServiceLocationException.PARSE_ERROR, 1277 "template_unk_token", 1278 new Object[] {Integer.toString(tk.lineno())}); 1279 1280 } 1281 1282 // Parse initial values. 1283 1284 if (!attDesc.getIsKeyword()) { 1285 1286 String tok = ""; 1287 1288 // Read in entire list. 1289 1290 do { 1291 int ptt = tt; 1292 lineno = tk.lineno(); 1293 tt = tk.nextToken(); 1294 1295 if (tt == StreamTokenizer.TT_WORD) { 1296 1297 // Trim line, check for '#', indicating end of list. 1298 1299 String line = tk.sval.trim(); 1300 1301 if (line.charAt(0) == TT_FIELD) { 1302 // it's help text already. 1303 1304 if (tok.length() > 0) { 1305 stk = 1306 new StreamTokenizer(new StringReader(tok)); 1307 parseDefaultValues(stk, attDesc, lineno); 1308 } 1309 1310 tk.pushBack(); 1311 break; 1312 1313 } else { 1314 1315 // Otherwise concatenate onto growing list. 1316 1317 tok = tok + line; 1318 1319 } 1320 1321 } else if (tt == StreamTokenizer.TT_EOL) { 1322 1323 if (ptt == StreamTokenizer.TT_EOL) { 1324 // end of attribute definition. 1325 1326 // Process any accumulated list. 1327 1328 if (tok.length() > 0) { 1329 stk = 1330 new StreamTokenizer(new StringReader(tok)); 1331 parseDefaultValues(stk, attDesc, lineno); 1332 } 1333 1334 return attDesc; 1335 1336 } 1337 } else if (tt == StreamTokenizer.TT_EOF) { 1338 throw 1339 new ServiceLocationException( 1340 ServiceLocationException.PARSE_ERROR, 1341 "template_end_error", 1342 new Object[] {Integer.toString(tk.lineno())}); 1343 1344 } else { 1345 1346 throw 1347 new ServiceLocationException( 1348 ServiceLocationException.PARSE_ERROR, 1349 "template_unk_token", 1350 new Object[] {Integer.toString(tk.lineno())}); 1351 1352 } 1353 1354 } while (true); 1355 1356 } else { 1357 attDesc.setDefaultValues(null); 1358 attDesc.setAllowedValues(null); 1359 1360 // Check for end of definition. 1361 1362 if ((tt = tk.nextToken()) == StreamTokenizer.TT_EOL) { 1363 return attDesc; 1364 1365 } else if (tt == StreamTokenizer.TT_WORD) { 1366 1367 // Check for start of help text. 1368 1369 String line = tk.sval.trim(); 1370 1371 if (line.charAt(0) != TT_FIELD) { 1372 throw 1373 new ServiceLocationException( 1374 ServiceLocationException.PARSE_ERROR, 1375 "template_attr_syntax", 1376 new Object[] {Integer.toString(tk.lineno())}); 1377 1378 } else { 1379 1380 tk.pushBack(); 1381 1382 } 1383 1384 } else if (tt == StreamTokenizer.TT_EOF) { 1385 throw 1386 new ServiceLocationException( 1387 ServiceLocationException.PARSE_ERROR, 1388 "template_end_error", 1389 new Object[] {Integer.toString(tk.lineno())}); 1390 1391 } else { 1392 1393 throw 1394 new ServiceLocationException( 1395 ServiceLocationException.PARSE_ERROR, 1396 "template_unk_token", 1397 new Object[] {Integer.toString(tk.lineno())}); 1398 1399 } 1400 } 1401 1402 1403 // Parse help text. 1404 1405 String helpText = ""; 1406 1407 do { 1408 int ptt = tt; 1409 lineno = tk.lineno(); 1410 tt = tk.nextToken(); 1411 1412 if (tt == StreamTokenizer.TT_WORD) { 1413 1414 // Check for end of help text. 1415 1416 String line = tk.sval.trim(); 1417 1418 if (line.charAt(0) == TT_FIELD) { 1419 1420 // Help text is collected verbatim after '#'. 1421 1422 helpText = 1423 helpText + line.substring(1) + "\n"; 1424 1425 } else { 1426 1427 // We've reached the end of the help text. Store it 1428 // and break out of the loop. 1429 1430 if (helpText.length() > 0) { 1431 attDesc.setDescription(helpText); 1432 } 1433 1434 tk.pushBack(); 1435 break; 1436 1437 } 1438 1439 } else if (tt == StreamTokenizer.TT_EOL || 1440 tt == StreamTokenizer.TT_EOF) { 1441 1442 // If previous token was end of line, quit. 1443 1444 if (ptt == StreamTokenizer.TT_EOL) { 1445 1446 // Store any text first. 1447 1448 if (helpText.length() > 0) { 1449 attDesc.setDescription(helpText); 1450 } 1451 1452 // If this is a keyword attribute, set the allowed 1453 // values list to null. 1454 1455 if (attDesc.getIsKeyword()) { 1456 attDesc.setAllowedValues(null); 1457 } 1458 1459 return attDesc; 1460 1461 } else if (tt == StreamTokenizer.TT_EOF) { 1462 1463 // Error if previous token wasn't EOL. 1464 1465 throw 1466 new ServiceLocationException( 1467 ServiceLocationException.PARSE_ERROR, 1468 "template_end_error", 1469 new Object[] {Integer.toString(tk.lineno())}); 1470 } 1471 1472 } else { 1473 1474 throw 1475 new ServiceLocationException( 1476 ServiceLocationException.PARSE_ERROR, 1477 "template_unk_token", 1478 new Object[] {Integer.toString(tk.lineno())}); 1479 } 1480 1481 } while (true); 1482 1483 // Parse allowed values. 1484 1485 if (!attDesc.getIsKeyword()) { 1486 1487 String tok = ""; 1488 1489 // Read in entire list. 1490 1491 do { 1492 int ptt = tt; 1493 lineno = tk.lineno(); 1494 tt = tk.nextToken(); 1495 1496 if (tt == StreamTokenizer.TT_WORD) { 1497 1498 // Concatenate onto growing list. 1499 1500 tok = tok + tk.sval; 1501 1502 } else if (tt == StreamTokenizer.TT_EOL) { 1503 1504 if (ptt == StreamTokenizer.TT_EOL) { 1505 // end of attribute definition. 1506 1507 // Process any accumulated list. 1508 1509 if (tok.length() > 0) { 1510 stk = 1511 new StreamTokenizer(new StringReader(tok)); 1512 parseAllowedValues(stk, attDesc, lineno); 1513 } 1514 1515 return attDesc; 1516 1517 } 1518 } else if (tt == StreamTokenizer.TT_EOF) { 1519 throw 1520 new ServiceLocationException( 1521 ServiceLocationException.PARSE_ERROR, 1522 "template_end_error", 1523 new Object[] {Integer.toString(tk.lineno())}); 1524 1525 } else { 1526 1527 throw 1528 new ServiceLocationException( 1529 ServiceLocationException.PARSE_ERROR, 1530 "template_unk_token", 1531 new Object[] {Integer.toString(tk.lineno())}); 1532 } 1533 1534 } while (true); 1535 1536 } else { 1537 1538 // Error. Keyword attribute should have ended during help text 1539 // parsing or before. 1540 1541 throw 1542 new ServiceLocationException( 1543 ServiceLocationException.PARSE_ERROR, 1544 "template_attr_syntax", 1545 new Object[] {Integer.toString(tk.lineno())}); 1546 } 1547 1548 } catch (IOException ex) { 1549 1550 throw 1551 new ServiceLocationException( 1552 ServiceLocationException.INTERNAL_SYSTEM_ERROR, 1553 "template_io_error", 1554 new Object[] { 1555 Integer.toString(tk.lineno()), 1556 ex.getMessage()}); 1557 } 1558 1559 } 1560 1561 // Check whether the default values, if any, are correct. 1562 checkDefaultValues(AttributeDescriptor attDesc)1563 private void checkDefaultValues(AttributeDescriptor attDesc) 1564 throws ServiceLocationException { 1565 1566 // Don't bother if it's a keyword attribute, parsing has checked. 1567 1568 if (attDesc.getIsKeyword()) { 1569 return; 1570 } 1571 1572 Enumeration init = attDesc.getDefaultValues(); 1573 Enumeration en = attDesc.getAllowedValues(); 1574 Vector allowed = new Vector(); 1575 String attDescType = attDesc.getValueType(); 1576 1577 // First, collect the allowed values. 1578 1579 while (en.hasMoreElements()) { 1580 Object allval = en.nextElement(); 1581 1582 // Lower case strings and create opaques for comparison 1583 // if type is opaque. 1584 1585 if (attDescType.equals(JAVA_STRING_TYPE)) { 1586 allval = ((String)allval).toLowerCase(); 1587 1588 } else if (attDescType.equals(JAVA_OPAQUE_TYPE)) { 1589 allval = new Opaque((byte[])allval); 1590 1591 } 1592 1593 allowed.addElement(allval); 1594 } 1595 1596 // Now compare the allowed with the initial. 1597 1598 if (allowed.size() > 0) { 1599 1600 // Error if allowed is restricted but no initializers. 1601 1602 if (!init.hasMoreElements()) { 1603 1604 throw 1605 new ServiceLocationException( 1606 ServiceLocationException.PARSE_ERROR, 1607 "template_no_init", 1608 new Object[] {attDesc.getId()}); 1609 1610 } 1611 1612 Object val = null; 1613 1614 // Compare init values with allowed. 1615 1616 while (init.hasMoreElements()) { 1617 Object test = init.nextElement(); 1618 val = test; // for exception.. 1619 1620 if (attDescType.equals(JAVA_STRING_TYPE)) { 1621 test = ((String)test).toLowerCase(); 1622 1623 } else if (attDescType.equals(JAVA_OPAQUE_TYPE)) { 1624 test = new Opaque((byte[])test); 1625 1626 } 1627 1628 if (allowed.indexOf(test) != -1) { 1629 return; // found it! 1630 } 1631 } 1632 // Initializer wasn't found. 1633 1634 throw 1635 new ServiceLocationException( 1636 ServiceLocationException.PARSE_ERROR, 1637 "template_wrong_init", 1638 new Object[] { 1639 val.toString(), attDesc.getId()}); 1640 } 1641 } 1642 1643 // Parse the attribute's id string. 1644 parseId(StreamTokenizer tk, AttributeDescriptor attDesc, int baseLineno)1645 private void parseId(StreamTokenizer tk, 1646 AttributeDescriptor attDesc, 1647 int baseLineno) 1648 throws ServiceLocationException, IOException { 1649 1650 // Parse the attribute's identifier tag. 1651 1652 String id = parseWord(tk, baseLineno); 1653 1654 int tt = tk.nextToken(); 1655 1656 // Parse the seperator. 1657 1658 if (tt != TT_EQUALS) { 1659 throw 1660 new ServiceLocationException( 1661 ServiceLocationException.PARSE_ERROR, 1662 "template_attr_syntax", 1663 new Object[] { 1664 Integer.toString(tk.lineno() + baseLineno)}); 1665 1666 } 1667 1668 // Expand out any escaped ``#''. It won't be handled by 1669 // SLA. 1670 1671 id = unescapeHash(id); 1672 1673 // Expand out character escapes. 1674 1675 id = 1676 ServiceLocationAttribute.unescapeAttributeString(id, true); 1677 1678 1679 attDesc.setId(id); 1680 } 1681 1682 // Parse the attribute's type and flags. 1683 1684 private void parseTypeAndFlags(StreamTokenizer tk, AttributeDescriptor attDesc, int baseLineno)1685 parseTypeAndFlags(StreamTokenizer tk, 1686 AttributeDescriptor attDesc, 1687 int baseLineno) 1688 throws ServiceLocationException, IOException { 1689 1690 int existingFlags = 0; 1691 1692 // Parse the attribute's type. 1693 1694 String type = parseWord(tk, baseLineno); 1695 1696 checkAndAddType(type, attDesc, tk.lineno() + baseLineno); 1697 1698 // Parse the flags. 1699 1700 do { 1701 1702 // Check if any flags are left. 1703 1704 if (tk.nextToken() == StreamTokenizer.TT_EOF) { 1705 break; 1706 1707 } else { 1708 tk.pushBack(); 1709 } 1710 1711 int lineno = tk.lineno(); 1712 1713 // Parse the flag. 1714 1715 String flag = parseWord(tk, baseLineno); 1716 1717 // Error if flags with keyword. 1718 1719 if (attDesc.getIsKeyword()) { 1720 throw 1721 new ServiceLocationException( 1722 ServiceLocationException.PARSE_ERROR, 1723 "template_attr_syntax", 1724 new Object[] { 1725 Integer.toString(tk.lineno() + baseLineno)}); 1726 } 1727 1728 1729 // Check and assign it to the attribute. 1730 1731 existingFlags = 1732 existingFlags | checkAndAddFlag(flag, 1733 existingFlags, 1734 attDesc, 1735 baseLineno + lineno); 1736 1737 } while (true); 1738 } 1739 1740 // Parse the attribute's initial value(s). 1741 parseDefaultValues(StreamTokenizer tk, AttributeDescriptor attDesc, int baseLineno)1742 private void parseDefaultValues(StreamTokenizer tk, 1743 AttributeDescriptor attDesc, 1744 int baseLineno) 1745 throws ServiceLocationException, IOException { 1746 1747 // First get the vector of initial values. 1748 1749 Vector vals = parseValueList(tk, attDesc, baseLineno); 1750 1751 // Check whether it works for this attribute. Type 1752 // checking will be done by value list parsing. 1753 1754 if (!attDesc.getIsMultivalued() && vals.size() > 1) { 1755 throw 1756 new ServiceLocationException( 1757 ServiceLocationException.PARSE_ERROR, 1758 "template_attr_syntax", 1759 new Object[] { 1760 Integer.toString(tk.lineno() + baseLineno)}); 1761 } 1762 1763 attDesc.setDefaultValues(vals); 1764 } 1765 1766 // Parse the attribute's allowed values. 1767 1768 private void parseAllowedValues(StreamTokenizer tk, AttributeDescriptor attDesc, int baseLineno)1769 parseAllowedValues(StreamTokenizer tk, 1770 AttributeDescriptor attDesc, 1771 int baseLineno) 1772 throws ServiceLocationException, IOException { 1773 1774 // First get the vector of all allowed values. 1775 1776 Vector vals = parseValueList(tk, attDesc, baseLineno); 1777 1778 // Now set the allowed value vector. 1779 1780 attDesc.setAllowedValues(vals); 1781 } 1782 1783 // Parse a value list. 1784 parseValueList(StreamTokenizer stk, AttributeDescriptor attDesc, int baseLineno)1785 private Vector parseValueList(StreamTokenizer stk, 1786 AttributeDescriptor attDesc, 1787 int baseLineno) 1788 throws ServiceLocationException, IOException { 1789 1790 Vector req = new Vector(); 1791 1792 // Set up the tokenizer according to the type of the 1793 // attribute. 1794 1795 String type = attDesc.getValueType(); 1796 1797 if (type.equals(JAVA_STRING_TYPE) || type.equals(JAVA_OPAQUE_TYPE)) { 1798 initStringItemChar(stk); 1799 } else if (type.equals(JAVA_INTEGER_TYPE)) { 1800 initIntItemChar(stk); 1801 } else if (type.equals(JAVA_BOOLEAN_TYPE)) { 1802 initIdChar(stk); 1803 } 1804 1805 // Parse through a potentially multivalued value list. 1806 1807 boolean wordRequired = true; // true when a word is required, 1808 // false when a comma required. 1809 boolean syntaxError = false; 1810 String reqTok = ""; 1811 int lineno = 0; 1812 1813 do { 1814 int tt = stk.nextToken(); 1815 lineno = stk.lineno() + baseLineno; 1816 1817 if (tt == StreamTokenizer.TT_WORD) { 1818 1819 // If a word isn't required, then the case is 1820 // "token token" and is an error. 1821 1822 if (!wordRequired) { 1823 syntaxError = true; 1824 } 1825 1826 reqTok = stk.sval.trim(); 1827 1828 // Convert the value to the proper object. 1829 1830 Object reqVal = convertValue(type, reqTok, baseLineno); 1831 req.addElement(reqVal); 1832 1833 wordRequired = false; 1834 1835 } else if (tt == StreamTokenizer.TT_EOF) { 1836 1837 // If a word is required, then list ends with 1838 // a comma, so error. 1839 1840 if (wordRequired) { 1841 syntaxError = true; 1842 } 1843 1844 break; 1845 1846 } else if (tt == TT_COMMA) { 1847 1848 // If a word is required, then error. The case is ",,". 1849 1850 if (wordRequired) { 1851 syntaxError = true; 1852 break; 1853 } 1854 1855 // Otherwise, the next token must be a word. 1856 1857 wordRequired = true; 1858 1859 } else { 1860 1861 // No other tokens are allowed. 1862 1863 syntaxError = true; 1864 break; 1865 } 1866 1867 } while (true); 1868 1869 if (syntaxError) { 1870 1871 throw 1872 new ServiceLocationException( 1873 ServiceLocationException.PARSE_ERROR, 1874 "template_attr_syntax", 1875 new Object[] {Integer.toString(lineno)}); 1876 } 1877 1878 return req; 1879 1880 } 1881 1882 // Check the type and add it to the attribute descriptor. 1883 checkAndAddType(String type, AttributeDescriptor attDesc, int lineno)1884 private void checkAndAddType(String type, 1885 AttributeDescriptor attDesc, 1886 int lineno) 1887 throws ServiceLocationException { 1888 1889 // Check token against recognized types. 1890 1891 if (type.equalsIgnoreCase(STRING_TYPE)) { 1892 attDesc.setValueType(JAVA_STRING_TYPE); 1893 1894 } else if (type.equalsIgnoreCase(INTEGER_TYPE)) { 1895 attDesc.setValueType(JAVA_INTEGER_TYPE); 1896 1897 } else if (type.equalsIgnoreCase(BOOLEAN_TYPE)) { 1898 attDesc.setValueType(JAVA_BOOLEAN_TYPE); 1899 1900 } else if (type.equalsIgnoreCase(OPAQUE_TYPE)) { 1901 attDesc.setValueType(JAVA_OPAQUE_TYPE); 1902 1903 } else if (type.equalsIgnoreCase(KEYWORD_TYPE)) { 1904 attDesc.setIsKeyword(true); 1905 1906 } else { 1907 1908 throw 1909 new ServiceLocationException( 1910 ServiceLocationException.PARSE_ERROR, 1911 "template_not_slp_type", 1912 new Object[] {Integer.toString(lineno)}); 1913 } 1914 1915 } 1916 1917 // Check the flag and add it to the attribute descriptor. 1918 checkAndAddFlag(String flag, int matched, AttributeDescriptor attDesc, int lineno)1919 private int checkAndAddFlag(String flag, 1920 int matched, 1921 AttributeDescriptor attDesc, 1922 int lineno) 1923 throws ServiceLocationException { 1924 1925 boolean duplicate = false; 1926 1927 // We depend on the attribute descriptor being initialized to 1928 // nothing, i.e. false for all flags and for keyword. 1929 1930 if (flag.equalsIgnoreCase(MULTIPLE_FLAG)) { 1931 1932 if ((matched & MULTIPLE_MASK) != 0) { 1933 duplicate = true; 1934 1935 } else { 1936 1937 // Check for boolean. Booleans may not have 1938 // multiple values. 1939 1940 if (attDesc.getValueType().equals(JAVA_BOOLEAN_TYPE)) { 1941 1942 throw 1943 new ServiceLocationException( 1944 ServiceLocationException.PARSE_ERROR, 1945 "template_boolean_multi", 1946 new Object[] {Integer.toString(lineno)}); 1947 } 1948 1949 attDesc.setIsMultivalued(true); 1950 return MULTIPLE_MASK; 1951 1952 } 1953 1954 } else if (flag.equalsIgnoreCase(LITERAL_FLAG)) { 1955 1956 if ((matched & LITERAL_MASK) != 0) { 1957 duplicate = true; 1958 1959 } else { 1960 attDesc.setIsLiteral(true); 1961 return LITERAL_MASK; 1962 } 1963 1964 } else if (flag.equalsIgnoreCase(EXPLICIT_FLAG)) { 1965 1966 if ((matched & EXPLICIT_MASK) != 0) { 1967 duplicate = true; 1968 1969 } else { 1970 attDesc.setRequiresExplicitMatch(true); 1971 return EXPLICIT_MASK; 1972 } 1973 1974 } else if (flag.equalsIgnoreCase(OPTIONAL_FLAG)) { 1975 1976 if ((matched & OPTIONAL_MASK) != 0) { 1977 duplicate = true; 1978 1979 } else { 1980 attDesc.setIsOptional(true); 1981 return OPTIONAL_MASK; 1982 } 1983 1984 } else { 1985 1986 throw 1987 new ServiceLocationException( 1988 ServiceLocationException.PARSE_ERROR, 1989 "template_invalid_attr_flag", 1990 new Object[] {Integer.toString(lineno)}); 1991 } 1992 1993 1994 if (duplicate) { 1995 throw 1996 new ServiceLocationException( 1997 ServiceLocationException.PARSE_ERROR, 1998 "template_dup_attr_flag", 1999 new Object[] {Integer.toString(lineno)}); 2000 } 2001 2002 return 0; // never happens. 2003 } 2004 2005 // Parse a word out of the tokenizer. The exact characters 2006 // will depend on what the syntax tables have been set to. 2007 parseWord(StreamTokenizer tk, int baseLineno)2008 private String parseWord(StreamTokenizer tk, int baseLineno) 2009 throws ServiceLocationException, IOException { 2010 2011 int tt = tk.nextToken(); 2012 2013 if (tt == StreamTokenizer.TT_WORD) { 2014 return (tk.sval); 2015 2016 } else { 2017 2018 String errorToken = ""; 2019 2020 // Report the erroneous characters. 2021 2022 if (tt == StreamTokenizer.TT_NUMBER) { 2023 errorToken = Double.toString(tk.nval); 2024 } else if (tt == StreamTokenizer.TT_EOL) { 2025 errorToken = "<end of line>"; 2026 } else if (tt == StreamTokenizer.TT_EOF) { 2027 errorToken = "<end of file>"; 2028 } else { 2029 errorToken = (Character.valueOf((char)tt)).toString(); 2030 } 2031 2032 throw 2033 new ServiceLocationException( 2034 ServiceLocationException.PARSE_ERROR, 2035 "template_invalid_tok", 2036 new Object[] { 2037 Integer.toString(tk.lineno() + baseLineno)}); 2038 2039 } 2040 2041 } 2042 2043 // Convert a value list token to the value. 2044 convertValue(String type, String reqTok, int lineno)2045 private Object convertValue(String type, 2046 String reqTok, 2047 int lineno) 2048 throws ServiceLocationException, 2049 IOException { 2050 2051 Object reqVal = null; 2052 2053 if (type.equals(JAVA_STRING_TYPE)) { 2054 2055 // Expand out any escaped ``#''. It won't be handled by 2056 // SLA. 2057 2058 reqTok = unescapeHash(reqTok); 2059 2060 // Expand out character escapes. 2061 2062 reqVal = 2063 ServiceLocationAttribute.unescapeAttributeString(reqTok, 2064 false); 2065 2066 } else if (type.equals(JAVA_INTEGER_TYPE)) { 2067 2068 try { 2069 2070 reqVal = Integer.valueOf(reqTok); 2071 2072 } catch (NumberFormatException ex) { 2073 2074 throw 2075 new ServiceLocationException( 2076 ServiceLocationException.PARSE_ERROR, 2077 "template_expect_int", 2078 new Object[] { 2079 Integer.toString(lineno), reqTok }); 2080 } 2081 } else if (type.equals(JAVA_BOOLEAN_TYPE)) { 2082 2083 // Boolean.valueOf() doesn't handle this properly. 2084 2085 if (reqTok.equalsIgnoreCase(TRUE_TOKEN)) { 2086 2087 reqVal = Boolean.valueOf(true); 2088 2089 } else if (reqTok.equalsIgnoreCase(FALSE_TOKEN)) { 2090 2091 reqVal = Boolean.valueOf(false); 2092 2093 } else { 2094 2095 throw 2096 new ServiceLocationException( 2097 ServiceLocationException.PARSE_ERROR, 2098 "template_expect_bool", 2099 new Object[] { 2100 Integer.toString(lineno), reqTok}); 2101 } 2102 } else if (type.equals(JAVA_OPAQUE_TYPE)) { 2103 2104 reqVal = Opaque.unescapeByteArray(reqTok); 2105 2106 } else { 2107 2108 Assert.slpassert(false, 2109 "template_attr_desc", 2110 new Object[0]); 2111 } 2112 2113 return reqVal; 2114 } 2115 2116 // Expand out any escaped hashes. Not handled by SLA. 2117 unescapeHash(String str)2118 private String unescapeHash(String str) { 2119 2120 StringBuffer buf = new StringBuffer(); 2121 int len = ESC_HASH.length(); 2122 int i, j = 0; 2123 2124 for (i = str.indexOf(ESC_HASH, j); 2125 i != -1; 2126 i = str.indexOf(ESC_HASH, j)) { 2127 2128 buf.append(str.substring(j, i)); 2129 buf.append(HASH); 2130 j = i + len; 2131 } 2132 2133 len = str.length(); 2134 2135 if (j < len) { 2136 buf.append(str.substring(j, len)); 2137 2138 } 2139 2140 return buf.toString(); 2141 } 2142 2143 } 2144