View Javadoc
1 /*** 2 * Copyright (c) 2002, CodeStreet LLC. All rights reserved. 3 * <p> 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * <p> 7 * Redistributions of source code must retain the above copyright notice, this 8 * list of conditions and the following disclaimer. Redistributions in binary 9 * form must reproduce the above copyright notice, this list of conditions and 10 * the following disclaimer in the documentation and/or other materials provided 11 * with the distribution. Neither the name of CodeStreet LLC. nor the names of 12 * its contributors may be used to endorse or promote products derived from this 13 * software without specific prior written permission. 14 * <p> 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * CONTRACT, STRICT LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 * <p> 27 */ 28 29 package com.codestreet.messageforge; 30 31 import java.util.ArrayList; 32 import java.util.List; 33 34 /*** 35 * Base class for all message classes. A message contains a collection of RFld 36 * instances. Each message implements a fast-fail strategy for field validations - 37 * i.e. a field is validated each time its value is set. To make sure that a 38 * message is valid it is still important to call {@link #validate()}to make 39 * sure that all non-optional fields have been set. 40 * <p> 41 * In the typical usage, a message object is defined via XML and the JAVA class 42 * for the message generated by the code-generator. In some other applications, 43 * it might be necessary to have the ability to create empty messages - messages 44 * with no fields - and add fields to these messages on the fly. Fields can be 45 * created explicitly or by using the <tt>RFldFactory</tt>. 46 * 47 * @author Jawaid Hakim. 48 */ 49 public class RMsg implements RMapMessage 50 { 51 static final long serialVersionUID = -6057031037833465192L; 52 53 //Generated by jserial 54 55 /*** 56 * Default constructor. Sets the empty message flag to <tt>true</tt>. 57 * 58 * @see #setEmptyMsg(boolean) 59 */ 60 public RMsg() 61 { 62 init(null, null); 63 setEmptyMsg(true); 64 } 65 66 /*** 67 * Constructor. 68 * 69 * @param name 70 * Message name. 71 * @param desc 72 * Description of message. 73 */ 74 public RMsg(String name, String desc) 75 { 76 init(name, desc); 77 } 78 79 /*** 80 * Create nested fields in message. All fields in the message are of type 81 * <tt>MSGOBJ</tt> or <tt>BEAN</tt> are created if not already set. 82 */ 83 public void createNested() 84 { 85 RFld[] flds = this.getFieldsAsArray(); 86 for (int i = 0; i < flds.length; ++i) 87 { 88 RFld fld = flds[i]; 89 if (fld.isValSet()) 90 continue; 91 92 if (fld.getType() == RFldType.MSGOBJ) 93 { 94 RFldMsgObj msgObjFld = (RFldMsgObj) fld; 95 Class cls = msgObjFld.getClassObject(); 96 if (cls != null) 97 { 98 try 99 { 100 RMsg newData = (RMsg) cls.newInstance(); 101 newData.createNested(); 102 msgObjFld.set(newData); 103 } 104 catch (FieldValidationException ex) 105 { 106 throw new RBaseRuntimeException(ex); 107 } 108 catch (InstantiationException ex) 109 { 110 throw new RBaseRuntimeException(ex); 111 } 112 catch (IllegalAccessException ex) 113 { 114 throw new RBaseRuntimeException(ex); 115 } 116 } 117 } 118 else if (fld.getType() == RFldType.BEAN) 119 { 120 RFldBean beanFld = (RFldBean) fld; 121 Class cls = beanFld.getClassType(); 122 if (cls != null) 123 { 124 try 125 { 126 Object newData = cls.newInstance(); 127 beanFld.set(newData); 128 } 129 catch (FieldValidationException ex) 130 { 131 throw new RBaseRuntimeException(ex); 132 } 133 catch (InstantiationException ex) 134 { 135 throw new RBaseRuntimeException(ex); 136 } 137 catch (IllegalAccessException ex) 138 { 139 throw new RBaseRuntimeException(ex); 140 } 141 } 142 } 143 } 144 } 145 146 /*** 147 * Initialize. 148 * 149 * @param desc 150 * Description of message. 151 */ 152 private void init(String name, String desc) 153 { 154 flds_ = new java.util.HashMap(); 155 if (noCaseFldNames_) 156 noCaseFlds_ = new java.util.HashMap(); 157 setDesc(desc); 158 setName(name); 159 } 160 161 /*** 162 * Get all fields in the message. 163 * 164 * @return Iterator of all RFld fields in the message. 165 */ 166 public final java.util.Iterator getFields() 167 { 168 return flds_.values().iterator(); 169 } 170 171 /*** 172 * Get all fields in the message. 173 * 174 * @return Array of all <tt>RFld</tt> fields in the message. 175 */ 176 public final RFld[] getFieldsAsArray() 177 { 178 if (fldsArray_ != null) 179 return fldsArray_; 180 return buildFieldsArray(); 181 } 182 183 /*** 184 * This method allows subclasses to signal that all fields have been added 185 * to the message. All subclasses should call this method after adding all 186 * fields to the message. 187 */ 188 protected final void doneAddingFields() 189 { 190 buildFieldsArray(); 191 } 192 193 /*** 194 * Get all fields in the message. 195 * 196 * @return Array of all <tt>RFld</tt> fields in the message. 197 */ 198 private final RFld[] buildFieldsArray() 199 { 200 fldsArray_ = new RFld[flds_.size()]; 201 int i = 0; 202 for (java.util.Iterator iter = getFields(); iter.hasNext();) 203 { 204 fldsArray_[i++] = (RFld) iter.next(); 205 } 206 207 return fldsArray_; 208 } 209 210 /*** 211 * Get a <tt>java.util.List</tt> with the names of all fields that have 212 * the specified search <tt>tag</tt> as one of their tags. 213 * 214 * @param searchTag 215 * Search tag. If the search tag is <tt>null</tt> then the 216 * names of all fields that do not have any tags are returned. 217 * @param ignoreCase 218 * Case insensitive tag compare is performed if this paramater is 219 * <tt>true</tt>. Otherwise, case sensitive tag compare is 220 * performed. 221 * @return <tt>java.util.List</tt> with the names of all fields whose 222 * <tt>tag</tt> matches the specified search <tt>tag</tt>. 223 * @see RFld#getTags() 224 * @see RFld#setTags(String[]) 225 */ 226 public final java.util.List getTaggedFields(String searchTag, 227 boolean ignoreCase) 228 { 229 java.util.List taggedFlds = new java.util.ArrayList(); 230 RFld[] fldsArray = getFieldsAsArray(); 231 for (int i = fldsArray.length - 1; i >= 0; --i) 232 { 233 RFld fld = fldsArray[i]; 234 String[] tags = fld.getTags(); 235 if (searchTag == null) 236 { 237 if (tags == null) 238 taggedFlds.add(fld.getName()); 239 } 240 else if (tags != null) 241 { 242 for (int j = tags.length - 1; j >= 0; --j) 243 { 244 String tag = tags[j]; 245 boolean equals = (ignoreCase) ? tag 246 .equalsIgnoreCase(searchTag) : tag 247 .equals(searchTag); 248 if (equals) 249 { 250 taggedFlds.add(fld.getName()); 251 break; 252 } 253 } 254 } 255 } 256 return taggedFlds; 257 } 258 259 /*** 260 * Reset all unlocked fields in the message. 261 * 262 * @see RFld#isLocked() 263 * @see RFld#reset() 264 */ 265 public final void resetFields() 266 { 267 RFld[] fldsArray = getFieldsAsArray(); 268 for (int i = fldsArray.length - 1; i >= 0; --i) 269 { 270 RFld fld = fldsArray[i]; 271 if (!fld.isLocked()) 272 { 273 try 274 { 275 fld.reset(); 276 } 277 catch (FieldValidationException ex) 278 { 279 // OK to eat up exception 280 } 281 } 282 } 283 } 284 285 /*** 286 * Set the field values of this message from another source message. A field 287 * in the source object will be copied if there is a field in the this 288 * object with the same name, and the source field has been set, and the 289 * target field is not locked. An implicit assumption is that if the source 290 * and the target have fields with the same name, then the types of the 291 * fields are the same - if this assumption is violated then an exception is 292 * thrown. 293 * 294 * @param another 295 * Source message. 296 * @see RFld#getType() 297 * @see #setFieldsIgnoreConstrained(RMsg) 298 */ 299 public final void setFields(RMsg another) throws FieldValidationException 300 { 301 setFields(another, false); 302 } 303 304 /*** 305 * Set the field values of this message from another source message. Fields 306 * in this message that have constraints are ignored. A field in the source 307 * object will be copied if there is a field in the this object with the 308 * same name, and the source field has been set, and the target field is not 309 * locked. An implicit assumption is that if the source and the target have 310 * fields with the same name, then the types of the fields are the same - if 311 * this assumption is violated then an exception is thrown. 312 * 313 * @param another 314 * Source message. 315 * @see RFld#getType() 316 * @see #setFields(RMsg) 317 */ 318 public final void setFieldsIgnoreConstrained(RMsg another) 319 throws FieldValidationException 320 { 321 setFields(another, true); 322 } 323 324 /*** 325 * Set the field values of this message from another source message. A field 326 * in the source object will be copied if there is a field in the this 327 * object with the same name, and the source field has been set, and the 328 * target field is not locked. An implicit assumption is that if the source 329 * and the target have fields with the same name, then the types of the 330 * fields are the same - if this assumption is violated then an exception is 331 * thrown. 332 * 333 * @param another 334 * Source message. 335 * @param ignoreConstrained 336 * Flagh to indicate whether constrained fields should be 337 * ignored. If <tt>true</tt> then fields that have constraints 338 * are not set. 339 * @see RFld#getType() 340 */ 341 protected final void setFields(RMsg another, boolean ignoreConstrained) 342 throws FieldValidationException 343 { 344 // Sanity check 345 if (this == another) 346 return; 347 348 StringBuffer errors = null; 349 RFld[] fldsArray = getFieldsAsArray(); 350 for (int i = fldsArray.length - 1; i >= 0; --i) 351 { 352 RFld fld = fldsArray[i]; 353 if (fld.isLocked() || (ignoreConstrained && fld.isConstrained())) 354 continue; 355 356 String fldName = fld.getName(); 357 if (another.fieldExists(fldName)) 358 { 359 RFld anotherFld = another.getField(fldName); 360 if (anotherFld.isValSet()) 361 { 362 try 363 { 364 fld.set(anotherFld.getValueAsObject()); 365 } 366 catch (FieldValidationException ex) 367 { 368 if (errors == null) 369 errors = new StringBuffer(128); 370 371 errors.append(ex.toString()).append(": ").append( 372 fldName).append('\n'); 373 } 374 } 375 } 376 } 377 if (errors != null) 378 throw new FieldValidationException(errors.toString()); 379 } 380 381 /*** 382 * Compare this message with another source message and return the names of 383 * all fields in the other message that are either not in this message or 384 * are in this message but have a different field type. 385 * 386 * @param another 387 * Source message. 388 * @return Array of field names. 389 * @see RFld#getType() 390 */ 391 public final Object[] diffFields(RMsg another) 392 throws FieldValidationException 393 { 394 // Sanity check 395 if (this == another) 396 return new Object[0]; 397 398 java.util.List result = new java.util.ArrayList(); 399 RFld[] fldsArray = getFieldsAsArray(); 400 for (int i = fldsArray.length - 1; i >= 0; --i) 401 { 402 RFld anotherFld = fldsArray[i]; 403 String anotherFldName = anotherFld.getName(); 404 if (fieldExists(anotherFldName)) 405 { 406 RFld thisFld = getField(anotherFldName); 407 if (thisFld.getType() != anotherFld.getType()) 408 result.add(anotherFldName); 409 } 410 else 411 result.add(anotherFldName); 412 } 413 414 // Create object array 415 return result.toArray(); 416 } 417 418 /*** 419 * Get message name. 420 * 421 * @return Message name. 422 */ 423 public final String getName() 424 { 425 return name_; 426 } 427 428 /*** 429 * Set message name. 430 * 431 * @param name 432 * Message name. 433 */ 434 protected final void setName(String name) 435 { 436 name_ = (name != null) ? name : RFldString.NA_VALUE; 437 } 438 439 /*** 440 * Get message description. 441 * 442 * @return Message description. 443 */ 444 public final String getDesc() 445 { 446 return desc_; 447 } 448 449 /*** 450 * Set message description. 451 * 452 * @param desc 453 * Message description. 454 */ 455 protected final void setDesc(String desc) 456 { 457 desc_ = (desc != null) ? desc : RFldString.NA_VALUE; 458 } 459 460 /*** 461 * Add a field to the message. 462 * 463 * @param fld 464 * Field to add to message. 465 * @see RFld 466 */ 467 public final void addField(RFld fld) throws FieldValidationException 468 { 469 String fldName = fld.getName(); 470 if (fieldExists(fldName)) 471 throw new FieldValidationException("Field already exists: " 472 + fldName); 473 474 flds_.put(fldName, fld); 475 if (noCaseFlds_ != null) 476 noCaseFlds_.put(fldName.toUpperCase(), fld); 477 478 // Since a new field was added invalidate the fields array - the fields 479 // array will be re-generated the next time someone asks for it. 480 fldsArray_ = null; 481 } 482 483 /*** 484 * Add a required group to the message. 485 * 486 * @param reqGrp 487 * Required group. 488 * @throws IllegalArgumentException 489 * if required group is <tt>null</tt>. 490 * @see RRequiredGrp 491 */ 492 protected final void addRequiredGrp(RRequiredGrp reqGrp) 493 { 494 if (reqGrp == null) 495 throw new java.lang.IllegalArgumentException("NULL required group"); 496 497 if (reqGrps_ == null) 498 reqGrps_ = new java.util.ArrayList(); 499 500 reqGrps_.add(reqGrp); 501 } 502 503 /*** 504 * Validate message. A message is valid if all its non-optional fields have 505 * been set. <br> 506 */ 507 public final void validate() throws FieldValidationException 508 { 509 String errMsg = validateMsg(this, null); 510 if (errMsg != null && errMsg.length() != 0) 511 { 512 errMsg = "\nMessage name = " + this.getName() + "\n" + errMsg; 513 throw new FieldValidationException(errMsg); 514 } 515 validateRequiredGrps(); 516 } 517 518 /*** 519 * Validate message. A message is valid if all its non-optional fields have 520 * been set. <br> 521 */ 522 public final void notRecuriveValidate() throws FieldValidationException 523 { 524 StringBuffer errors = null; 525 RFld[] fldsArray = getFieldsAsArray(); 526 for (int i = fldsArray.length - 1; i >= 0; --i) 527 { 528 // Make sure that all non-optional fields have been set 529 RFld fld = fldsArray[i]; 530 if (fld.isValSet() || fld.getOptional()) 531 continue; 532 533 if (errors == null) 534 errors = new StringBuffer(128); 535 errors.append("\tRequired field not set: ").append(fld.getName()) 536 .append('\n'); 537 } 538 if (errors != null) 539 throw new FieldValidationException(errors.toString()); 540 541 validateRequiredGrps(); 542 } 543 544 /*** 545 * Recusively validiate the RMsg 546 * 547 * @param msg 548 * The RMsg to validate 549 * @param outerFieldNameList 550 * a way to keep track of the fieldname during recursion. 551 * @return Returns error if any field in message in invalid. Returns empty 552 * string if message is valid. 553 */ 554 public static String validateMsg(RMsg msg, List outerFieldNameList) 555 { 556 String err = ""; 557 RFld[] fldsArray = msg.getFieldsAsArray(); 558 for (int i = 0; i < fldsArray.length; i++) 559 { 560 err = validateFld(fldsArray[i], outerFieldNameList); 561 if (err != null) 562 break; 563 } 564 return err; 565 } 566 567 /*** 568 * If the field contains another RMsg, then call validateMsg, otherwise just 569 * check if all not optional fields were set. 570 * 571 * @param fld 572 * The RFld to validate. 573 * @param outerFieldNameList 574 * a way to keep track of the fieldname during recursion. 575 */ 576 public static String validateFld(RFld fld, List outerFieldNameList) 577 { 578 String errors = null; 579 if (fld.isValSet()) 580 { 581 if (fld.getType().equals(RFldType.MSGOBJ)) 582 { 583 if (outerFieldNameList == null) 584 outerFieldNameList = new ArrayList(); 585 String outerFldName = fld.getName() + "."; 586 outerFieldNameList.add(outerFldName); 587 errors = validateMsg(((RFldMsgObj) fld).getValue(), 588 outerFieldNameList); 589 outerFieldNameList.remove(outerFldName); 590 } 591 } 592 else if (!fld.getOptional()) 593 { 594 String outerFieldName = convertList(outerFieldNameList); 595 errors = "Required field <" + outerFieldName + fld.getName() 596 + "> not set\n"; 597 } 598 return errors; 599 } 600 601 private static String convertList(List list) 602 { 603 String ret = ""; 604 if (list != null) 605 { 606 StringBuffer sb = new StringBuffer(); 607 for (int i = 0; i < list.size(); i++) 608 { 609 sb.append(list.get(i)); 610 } 611 ret = sb.toString(); 612 } 613 return ret; 614 } 615 616 /*** 617 * Validate required field groups. 618 */ 619 public final void validateRequiredGrps() throws FieldValidationException 620 { 621 if (reqGrps_ == null) 622 return; 623 624 for (int i = reqGrps_.size() - 1; i >= 0; --i) 625 { 626 RRequiredGrp reqGrp = (RRequiredGrp) reqGrps_.get(i); 627 String[] condFldNames = reqGrp.getConditionalFields(); 628 String[] condFldValues = reqGrp.getConditionalValues(); 629 630 // Sanity check 631 if (condFldNames.length != condFldValues.length) 632 throw new FieldValidationException( 633 "Conditional field name/value count mismatch"); 634 635 // Check if all conditional fields are set to their specified value 636 boolean enabled = true; 637 for (int j = 0; j < condFldNames.length; ++j) 638 { 639 RFld condFld = getField(condFldNames[j]); 640 if (!condFld.isValSet()) 641 throw new FieldValidationException( 642 "Conditional field not set: " + condFld.getName()); 643 644 String condValue = condFldValues[j]; 645 if (condFld instanceof RFldString) 646 { 647 RFldString fldStr = (RFldString) condFld; 648 if (!condValue.equals(fldStr.getValue())) 649 { 650 enabled = false; 651 break; 652 } 653 } 654 else if (condFld instanceof RFldBool) 655 { 656 RFldBool fldBool = (RFldBool) condFld; 657 if (Boolean.valueOf(condValue).booleanValue() != fldBool 658 .getValue()) 659 { 660 enabled = false; 661 break; 662 } 663 } 664 else if (condFld instanceof RFldNumeric) 665 { 666 // TODO: handle numeric fields. 667 throw new FieldValidationException("Not implemented"); 668 } 669 } 670 671 // If the conditional trigger is enabled then make sure 672 // the required fields are set. 673 if (enabled) 674 { 675 String[] reqFlds = reqGrp.getRequiredFields(); 676 for (int j = reqFlds.length - 1; j >= 0; --j) 677 { 678 RFld reqFld = getField(reqFlds[j]); 679 if (!reqFld.isValSet()) 680 throw new FieldValidationException("Field not set: " 681 + reqFlds[j]); 682 } 683 } 684 } 685 } 686 687 /*** 688 * Apply a functor to all fields in the message. 689 * 690 * @param func 691 * Functor 692 * @return The number of fields to which the functor was applied. 693 * @see RFunctor 694 */ 695 public final int apply(RFunctor func) throws FieldValidationException 696 { 697 RFld[] fldsArray = getFieldsAsArray(); 698 for (int i = fldsArray.length - 1; i >= 0; --i) 699 func.apply(fldsArray[i]); 700 701 return fldsArray.length; 702 } 703 704 /*** 705 * Apply a functor to a named field in the message. 706 * 707 * @param func 708 * Functor. 709 * @param fldName 710 * Field name. 711 * @return <tt>true</tt> if the named field was found and the functor was 712 * applied to it. 713 * @see RFunctor 714 */ 715 public final boolean apply(RFunctor func, String fldName) 716 throws FieldValidationException 717 { 718 func.apply(getField(fldName)); 719 return true; 720 } 721 722 /*** 723 * Get a named field from this message. Returns <tt>null</tt> if the named 724 * field is not in the message. Either there is an exact match for the field 725 * name, or, case-insentitive names are enabled and there is a 726 * case-insensitive field name match. 727 * 728 * @param fldName 729 * Field name. 730 * @return Named field. 731 */ 732 public final RFld getFieldIfExists(String fldName) 733 throws FieldValidationException 734 { 735 RFld fld = (RFld) flds_.get(fldName); 736 if (fld == null && noCaseFlds_ != null) 737 fld = (RFld) noCaseFlds_.get(fldName.toUpperCase()); 738 739 return fld; 740 } 741 742 /*** 743 * Get a named field from this message. Throws an exception if the named 744 * field is not in the message. Either there is an exact match for the field 745 * name, or, case-insentitive names are enabled and there is a 746 * case-insensitive field name match. 747 * 748 * @param fldName 749 * Field name. 750 * @return Named field. 751 */ 752 public final RFld getField(String fldName) throws FieldValidationException 753 { 754 RFld fld = getFieldIfExists(fldName); 755 if (fld != null) 756 return fld; 757 758 throw new FieldValidationException("Field not found in message: " 759 + fldName); 760 } 761 762 /*** 763 * Get Lock/Unlock property of the message object. If a message is locked 764 * then all the setter methods are disabled. 765 * 766 * @return Returns <tt>true</tt> if object is locked. Otherwise, returns 767 * <tt>false</tt>. 768 */ 769 public final boolean isLocked() 770 { 771 return locked_; 772 } 773 774 /*** 775 * Lock/Unlock the message object and all its fields. 776 * 777 * @param locked 778 * <tt>true</tt> to lock the object. Otherwise, <tt>false</tt> 779 * to unlock the object. 780 */ 781 public final void setLocked(boolean locked) 782 { 783 // Lock message and all fields. 784 locked_ = locked; 785 RFld[] fldsArray = getFieldsAsArray(); 786 for (int i = fldsArray.length - 1; i >= 0; --i) 787 fldsArray[i].setLocked(locked); 788 } 789 790 /*** 791 * Check if the send subject has been fixed. 792 * 793 * @return Returns <tt>true</tt> if the send subject has been fixed. 794 * Otherwise, returns <tt>false</tt>. 795 * @see #setSendSubject(String) 796 * @see #clearSendSubject() 797 */ 798 public final boolean isSendSubjectFixed() 799 { 800 return (fixedSendSubject_ != null); 801 } 802 803 /*** 804 * Clears the send subject if it has been fixed. 805 * 806 * @see #isSendSubjectFixed() 807 * @see #setSendSubject(String) 808 */ 809 public final void clearSendSubject() 810 { 811 fixedSendSubject_ = null; 812 } 813 814 /*** 815 * Set the send subject. Once the send subject has been fixed, it is not 816 * re-computed at run time, and is instead used for single and multiple send 817 * subjects. 818 * 819 * @param fixedSendSubject 820 * Fixed send subject. 821 * @see #isSendSubjectFixed() 822 * @see #clearSendSubject() 823 */ 824 public final void setSendSubject(String fixedSendSubject) 825 { 826 fixedSendSubject_ = fixedSendSubject; 827 } 828 829 /*** 830 * Set subject parameters. 831 * 832 * @param params 833 * Map of parameter placeholder values. Key into the hashtable is 834 * the name of the placeholder and the value is the value of the 835 * placeholder. Parameter values in this parameter override field 836 * value substitution. <br> 837 * For example, suppose the parameterized subject specification 838 * is <tt>UM.[ClientId].ADMIN</tt>, and the message has a 839 * field named <tt>ClientId</tt> with value <tt>JPM</tt>. If 840 * a key/value <tt>ClientId/BARZ</tt> is passed here then the 841 * send subject will be <tt>UM.BARZ.ADMIN</tt>. If the 842 * key/value is not passed then the send subject will be 843 * <tt>UM.JPM.ADMIN</tt>. 844 * @see #setSendSubject(String) 845 * @see #getSendSubject() 846 * @see #getSendSubject(java.util.Hashtable) 847 * @see #getSendSubjects() 848 * @see #getSendSubjects(java.util.Hashtable) 849 * @see #getListenSubject(boolean) 850 * @see #getListenSubject(java.util.Hashtable, boolean) 851 * @see #getListenSubjects(boolean) 852 * @see #getListenSubjects(java.util.Hashtable, boolean) 853 */ 854 public final synchronized static void setSubjectParams( 855 java.util.Hashtable params) 856 { 857 subjectParams_ = params; 858 } 859 860 /*** 861 * Determine if the message has exactly one subject specification. 862 * 863 * @return Returns <tt>true</tt> if the message has exactly one subject 864 * specification. Returns <tt>false</tt> if the message has zero 865 * or more than one subject specification. 866 * @see #setSendSubject(String) 867 * @see #getSendSubject() 868 * @see #getSendSubject(java.util.Hashtable) 869 * @see #getSendSubjects() 870 * @see #getSendSubjects(java.util.Hashtable) 871 * @see #getListenSubject(boolean) 872 * @see #getListenSubject(java.util.Hashtable, boolean) 873 * @see #getListenSubjects(boolean) 874 * @see #getListenSubjects(java.util.Hashtable, boolean) 875 */ 876 public final boolean hasOneSubjectSpec() 877 { 878 return (subjectSpec_ != null && subjectSpec_.length == 1); 879 } 880 881 /*** 882 * Set the subject specification. More then one subject specification can be 883 * set with each specification separated by the SUBJECT_DELIMITER. 884 * 885 * @param subjectSpec 886 * One or more subject specifications separated by 887 * SUBJECT_DELIMITER. 888 * @see #setSendSubject(String) 889 * @see #getSendSubject() 890 * @see #getSendSubject(java.util.Hashtable) 891 * @see #getSendSubjects() 892 * @see #getSendSubjects(java.util.Hashtable) 893 * @see #getListenSubject(boolean) 894 * @see #getListenSubject(java.util.Hashtable, boolean) 895 * @see #getListenSubjects(boolean) 896 * @see #getListenSubjects(java.util.Hashtable, boolean) 897 * @see #SUBJECT_DELIMITER 898 */ 899 protected final void setSubjectSpec(String[] subjectSpec, 900 String[][] subjectSpecComponents) 901 { 902 subjectSpec_ = subjectSpec; 903 subjectSpecComponents_ = subjectSpecComponents; 904 } 905 906 /*** 907 * Get the subject specifications. 908 * 909 * @return Subject specifications. 910 * @see #setSendSubject(String) 911 * @see #getSendSubject() 912 * @see #getSendSubject(java.util.Hashtable) 913 * @see #getSendSubjects() 914 * @see #getSendSubjects(java.util.Hashtable) 915 * @see #getListenSubject(boolean) 916 * @see #getListenSubject(java.util.Hashtable, boolean) 917 * @see #getListenSubjects(boolean) 918 * @see #getListenSubjects(java.util.Hashtable, boolean) 919 */ 920 public final String[] getSubjectSpec() 921 { 922 return subjectSpec_; 923 } 924 925 /*** 926 * Get the send subject for this message. Throws an exception if the message 927 * does not have exactly one send subject. 928 * 929 * @return Send subject for this message. 930 * @see #setSendSubject(String) 931 * @see #getSendSubject(java.util.Hashtable) 932 * @see #getSendSubjects() 933 * @see #getSendSubjects(java.util.Hashtable) 934 * @see #getListenSubject(boolean) 935 * @see #getListenSubject(java.util.Hashtable, boolean) 936 * @see #getListenSubjects(boolean) 937 * @see #getListenSubjects(java.util.Hashtable, boolean) 938 */ 939 public final String getSendSubject() throws MsgValidationException 940 { 941 if (hasOneSubjectSpec() || isSendSubjectFixed()) 942 return buildSubject(null, false, 0); 943 else if (subjectSpec_ != null && subjectSpec_.length > 0) 944 throw new MsgValidationException( 945 "Message has multiple send subjects"); 946 else 947 throw new MsgValidationException("Message has no send subject"); 948 } 949 950 /*** 951 * Get the send subject for this message. Throws an exception if the message 952 * does not have exactly one send subject. 953 * 954 * @param params 955 * Map of parameter placeholder values. Key into the hashtable is 956 * the name of the placeholder and the value is the value of the 957 * placeholder. Parameter values in this parameter override field 958 * value substitution. <br> 959 * For example, suppose the parameterized subject specification 960 * is <tt>UM.[ClientId].ADMIN</tt>, and the message has a 961 * field named <tt>ClientId</tt> with value <tt>JPM</tt>. If 962 * a key/value <tt>ClientId/BARZ</tt> is passed here then the 963 * send subject will be <tt>UM.BARZ.ADMIN</tt>. If the 964 * key/value is not passed then the send subject will be 965 * <tt>UM.JPM.ADMIN</tt>. 966 * @return Send subject for this message. 967 * @see #setSendSubject(String) 968 * @see #getSendSubject() 969 * @see #getSendSubjects() 970 * @see #getSendSubjects(java.util.Hashtable) 971 * @see #getListenSubject(boolean) 972 * @see #getListenSubject(java.util.Hashtable, boolean) 973 * @see #getListenSubjects(boolean) 974 * @see #getListenSubjects(java.util.Hashtable, boolean) 975 */ 976 public final String getSendSubject(java.util.Hashtable params) 977 throws MsgValidationException 978 { 979 if (hasOneSubjectSpec() || isSendSubjectFixed()) 980 return buildSubject(params, false, 0); 981 else if (subjectSpec_ != null && subjectSpec_.length > 0) 982 throw new MsgValidationException( 983 "Message has multiple send subjects"); 984 else 985 throw new MsgValidationException("Message has no send subject"); 986 } 987 988 /*** 989 * Get the send subjects for this message. Throws an exception if the 990 * message does not have any send subjects. 991 * 992 * @return Send subject for this message. 993 * @see #setSendSubject(String) 994 * @see #getSendSubject() 995 * @see #getSendSubject(java.util.Hashtable) 996 * @see #getSendSubjects(java.util.Hashtable) 997 * @see #getListenSubject(boolean) 998 * @see #getListenSubject(java.util.Hashtable, boolean) 999 * @see #getListenSubjects(boolean) 1000 * @see #getListenSubjects(java.util.Hashtable, boolean) 1001 */ 1002 public final String[] getSendSubjects() throws MsgValidationException 1003 { 1004 String[] sendSubjects = getSubjects(null, false); 1005 if (sendSubjects.length != 0) 1006 return sendSubjects; 1007 1008 throw new MsgValidationException("Message has no send subjects"); 1009 } 1010 1011 /*** 1012 * Get the send subjects for this message. Throws an exception if the 1013 * message does not have any send subject. 1014 * 1015 * @param params 1016 * Map of parameter placeholder values. Key into the hashtable is 1017 * the name of the placeholder and the value is the value of the 1018 * placeholder. Parameter values in this parameter override field 1019 * value substitution. <br> 1020 * For example, suppose the parameterized subject specification 1021 * is <tt>UM.[ClientId].ADMIN</tt>, and the message has a 1022 * field named <tt>ClientId</tt> with value <tt>JPM</tt>. If 1023 * a key/value <tt>ClientId/BARZ</tt> is passed here then the 1024 * send subject will be <tt>UM.BARZ.ADMIN</tt>. If the 1025 * key/value is not passed then the send subject will be 1026 * <tt>UM.JPM.ADMIN</tt>. 1027 * @return Send subjects for this message. 1028 * @see #setSendSubject(String) 1029 * @see #getSendSubject() 1030 * @see #getSendSubject(java.util.Hashtable) 1031 * @see #getSendSubjects() 1032 * @see #getListenSubject(boolean) 1033 * @see #getListenSubject(java.util.Hashtable, boolean) 1034 * @see #getListenSubjects(boolean) 1035 * @see #getListenSubjects(java.util.Hashtable, boolean) 1036 */ 1037 public final String[] getSendSubjects(java.util.Hashtable params) 1038 throws MsgValidationException 1039 { 1040 String[] sendSubjects = getSubjects(params, false); 1041 if (sendSubjects.length != 0) 1042 return sendSubjects; 1043 1044 throw new MsgValidationException("Message has no send subjects"); 1045 } 1046 1047 /*** 1048 * Get the listen subject for this message. Throws an exception if the 1049 * message does not have exactly one listen subject. 1050 * 1051 * @param wildcard 1052 * If <tt>true</tt> all parameterized components in the subject 1053 * specification are converted into wildcard '*'. 1054 * @return Listen subjects for this message. 1055 * @see #setSendSubject(String) 1056 * @see #getSendSubject() 1057 * @see #getSendSubject(java.util.Hashtable) 1058 * @see #getSendSubjects() 1059 * @see #getSendSubjects(java.util.Hashtable) 1060 * @see #getListenSubject(java.util.Hashtable, boolean) 1061 * @see #getListenSubjects(boolean) 1062 * @see #getListenSubjects(java.util.Hashtable, boolean) 1063 */ 1064 public final String getListenSubject(boolean wildcard) 1065 throws MsgValidationException 1066 { 1067 if (hasOneSubjectSpec() || isSendSubjectFixed()) 1068 return buildSubject(null, wildcard, 0); 1069 else if (subjectSpec_.length > 0) 1070 throw new MsgValidationException( 1071 "Message has multiple listen subjects"); 1072 else 1073 throw new MsgValidationException("Message has no listen subject"); 1074 } 1075 1076 /*** 1077 * Get the listen subject for this message. Throws an exception if the 1078 * message does not have exactly one listen subject. 1079 * 1080 * @param params 1081 * Map of parameter placeholder values. Key into the hashtable is 1082 * the name of the placeholder and the value is the value of the 1083 * placeholder. Values in this parameter override field value 1084 * substitution. <br> 1085 * For example, suppose the parameterized subject specification 1086 * is <tt>UM.[ClientId].ADMIN</tt>, and the message has a 1087 * field named <tt>ClientId</tt> with value <tt>JPM</tt>. If 1088 * a key/value <tt>ClientId/BARZ</tt> is passed here then the 1089 * listen subject will be <tt>UM.BARZ.ADMIN</tt>. If the 1090 * key/value is not passed then the listen subject will be 1091 * <tt>UM.JPM.ADMIN</tt>. 1092 * @param wildcard 1093 * If <tt>true</tt> all parameterized components in the subject 1094 * specification are converted into wildcard '*'. 1095 * @return Listen subjects for this message. 1096 * @see #setSendSubject(String) 1097 * @see #getSendSubject() 1098 * @see #getSendSubject(java.util.Hashtable) 1099 * @see #getSendSubjects() 1100 * @see #getSendSubjects(java.util.Hashtable) 1101 * @see #getListenSubject(boolean) 1102 * @see #getListenSubjects(boolean) 1103 * @see #getListenSubjects(java.util.Hashtable, boolean) 1104 */ 1105 public final String getListenSubject(java.util.Hashtable params, 1106 boolean wildcard) throws MsgValidationException 1107 { 1108 if (hasOneSubjectSpec()) 1109 return buildSubject(params, wildcard, 0); 1110 else if (subjectSpec_.length > 0) 1111 throw new MsgValidationException( 1112 "Message has multiple listen subjects"); 1113 else 1114 throw new MsgValidationException("Message has no listen subject"); 1115 } 1116 1117 /*** 1118 * Get the listen subjects for this message. Throws an exception if the 1119 * message does not have any listen subject. 1120 * 1121 * @param wildcard 1122 * If <tt>true</tt> all parameterized components in the subject 1123 * specification are converted into wildcard '*'. 1124 * @return Listen subjects for this message. 1125 * @see #setSendSubject(String) 1126 * @see #getSendSubject() 1127 * @see #getSendSubject(java.util.Hashtable) 1128 * @see #getSendSubjects() 1129 * @see #getSendSubjects(java.util.Hashtable) 1130 * @see #getListenSubject(boolean) 1131 * @see #getListenSubject(java.util.Hashtable, boolean) 1132 * @see #getListenSubjects(java.util.Hashtable, boolean) 1133 */ 1134 public final String[] getListenSubjects(boolean wildcard) 1135 throws MsgValidationException 1136 { 1137 String[] listenSubjects = getSubjects(null, wildcard); 1138 if (listenSubjects.length != 0) 1139 return listenSubjects; 1140 1141 throw new MsgValidationException("Message has no listen subjects"); 1142 } 1143 1144 /*** 1145 * Get the listen subjects for this message. Throws an exception if the 1146 * message does not have exactly any listen subject. 1147 * 1148 * @param params 1149 * Map of parameter placeholder values. Key into the hashtable is 1150 * the name of the placeholder and the value is the value of the 1151 * placeholder. Values in this parameter override field value 1152 * substitution. <br> 1153 * For example, suppose the parameterized subject specification 1154 * is <tt>UM.[ClientId].ADMIN</tt>, and the message has a 1155 * field named <tt>ClientId</tt> with value <tt>JPM</tt>. If 1156 * a key/value <tt>ClientId/BARZ</tt> is passed here then the 1157 * listen subject will be <tt>UM.BARZ.ADMIN</tt>. If the 1158 * key/value is not passed then the listen subject will be 1159 * <tt>UM.JPM.ADMIN</tt>. 1160 * @param wildcard 1161 * If <tt>true</tt> all parameterized components in the subject 1162 * specification are converted into wildcard '*'. 1163 * @return Listen subjects for this message. 1164 * @see #setSendSubject(String) 1165 * @see #getSendSubject() 1166 * @see #getSendSubject(java.util.Hashtable) 1167 * @see #getSendSubjects() 1168 * @see #getSendSubjects(java.util.Hashtable) 1169 * @see #getListenSubject(boolean) 1170 * @see #getListenSubject(java.util.Hashtable, boolean) 1171 * @see #getListenSubjects(boolean) 1172 */ 1173 public final String[] getListenSubjects(java.util.Hashtable params, 1174 boolean wildcard) throws MsgValidationException 1175 { 1176 String[] listenSubjects = getSubjects(params, wildcard); 1177 if (listenSubjects.length != 0) 1178 return listenSubjects; 1179 1180 throw new MsgValidationException("Message has no listen subjects"); 1181 } 1182 1183 /*** 1184 * Build subjects for this message. 1185 * 1186 * @param params 1187 * @param wildcard 1188 * Flag to indicate if parameterized subject components should be 1189 * converted to wildcard '*'. If <tt>true</tt> then all the 1190 * parameterized subject components are converted to wildcard. 1191 * @return Subjects for this message. Returns <tt>zero length</tt> array 1192 * if the message does not have any subject specification. 1193 */ 1194 protected final String[] getSubjects(java.util.Hashtable params, 1195 boolean wildcard) throws MsgValidationException 1196 { 1197 if (subjectSpec_ == null || subjectSpec_.length == 0) 1198 return NOSUBJECT_ARRAY; 1199 1200 String[] sendSubjects = new String[subjectSpec_.length]; 1201 for (int specIndex = subjectSpec_.length - 1; specIndex >= 0; --specIndex) 1202 sendSubjects[specIndex] = buildSubject(params, wildcard, specIndex); 1203 1204 return sendSubjects; 1205 } 1206 1207 /*** 1208 * Build the subject from the subject specification. 1209 * 1210 * @param params 1211 * Map of parameter placeholder values. 1212 * @param wildcard 1213 * Flag to indicate if parameterized subject components should be 1214 * converted to wildcard '*'. If <tt>true</tt> then all the 1215 * parameterized subject components are converted to wildcard. 1216 * @param specIndex 1217 * Subject specification index. 1218 * @return Send subject. 1219 */ 1220 private final String buildSubject(java.util.Hashtable params, 1221 boolean wildcard, int specIndex) throws MsgValidationException 1222 { 1223 // If wildcard is false - i.e. this request is not for a send subject 1224 // since send 1225 // subjects cannot have wildacards - and the fixed send subject has 1226 // been set then 1227 // return the fixed send subject 1228 if (!wildcard && fixedSendSubject_ != null) 1229 return fixedSendSubject_; 1230 1231 if (specIndex < 0 || specIndex > subjectSpec_.length) 1232 throw new MsgValidationException( 1233 "Subject specification index out of bounds: " + specIndex); 1234 1235 StringBuffer wrkSpace = new StringBuffer(); 1236 StringBuffer expression = new StringBuffer(); 1237 String subject = subjectSpec_[specIndex]; 1238 for (int componentIndex = subjectSpecComponents_[specIndex].length - 1; componentIndex >= 0; --componentIndex) 1239 { 1240 String component = subjectSpecComponents_[specIndex][componentIndex]; 1241 1242 // The subject component can be one of two types. The first type is 1243 // a direct name, and the second type is an indirect name. 1244 1245 // A direct name is simply a key that is used to look up an entry 1246 // in the 1247 // maps or in the message itself. For example, a direct name 1248 // component 1249 // might be [ClientId]. 1250 1251 // An indirect name consists of two parts - the second part is an 1252 // identifier 1253 // that is used to look to look up an entry in the maps or in the 1254 // message itself. 1255 // If an entry is found, then the value of that entry is used to do 1256 // another lookup. 1257 // The value of the second lookup is used to fill the subject 1258 // component. For 1259 // example, an indirect name component might be 1260 // [FGG:RoutingDestination]. For this 1261 // indirect name component, the key RoutingDestination will be used 1262 // to look up the 1263 // value. Suppose there is a field named RoutingDestination in the 1264 // message with 1265 // the value 'FGNY'. In that case, the value 'FGNY' will be used to 1266 // do another 1267 // lookup. Suppose the value of the key 'FGNY' in the map is 'FG1' 1268 // - that will be 1269 // value of the subject component [FGG:RoutingDestination]. 1270 String replacement = null; 1271 int indirectLookup = component 1272 .indexOf(INDIRECT_COMPONENT_DELIMITER); 1273 if (indirectLookup < 0) 1274 { 1275 // Direct name 1276 replacement = getReplacement(params, wildcard, component); 1277 } 1278 else 1279 { 1280 // Indirect name - extract lookup name 1281 String subComponent = component.substring(indirectLookup + 1); 1282 1283 // First lookup 1284 replacement = getReplacement(params, wildcard, subComponent); 1285 1286 // Second lookup 1287 replacement = getReplacement(params, wildcard, replacement); 1288 } 1289 1290 // Zap out previous expression and build new one 1291 expression.setLength(0); 1292 expression.append(SUBJECT_PARAM_START).append(component).append( 1293 SUBJECT_PARAM_END); 1294 1295 subject = substitute(subject, expression.toString(), replacement, 1296 wrkSpace); 1297 } 1298 return subject; 1299 } 1300 1301 /*** 1302 * Create the replacement string for a subject name component. 1303 * 1304 * @param params 1305 * Map of parameter placeholder values. 1306 * @param wildcard 1307 * Flag to indicate if parameterized subject components should be 1308 * converted to wildcard '*'. If <tt>true</tt> then all the 1309 * parameterized subject components are converted to wildcard. 1310 * @param component 1311 * Subject name component. 1312 */ 1313 private final String getReplacement(java.util.Hashtable params, 1314 boolean wildcard, String component) throws MsgValidationException 1315 { 1316 if (wildcard) 1317 { 1318 return SUBJECT_WILDCARD; 1319 } 1320 else if (params != null && params.containsKey(component)) 1321 { 1322 return (String) params.get(component); 1323 } 1324 else if (subjectParams_ != null 1325 && subjectParams_.containsKey(component)) 1326 { 1327 return (String) subjectParams_.get(component); 1328 } 1329 else if (fieldExists(component)) 1330 { 1331 try 1332 { 1333 RFld fld = getField(component); 1334 if (fld.isValSet()) 1335 return fld.getValueAsString(); 1336 1337 throw new MsgValidationException("Field not set: " + component); 1338 } 1339 catch (FieldValidationException ex) 1340 { 1341 throw new MsgValidationException(ex); 1342 } 1343 } 1344 else 1345 throw new MsgValidationException( 1346 "Unknown component in subject specification: " + component); 1347 } 1348 1349 /*** 1350 * Substitute all occurances of a match string by a replacement string in a 1351 * source string. 1352 * 1353 * @param source 1354 * Source string. 1355 * @param match 1356 * Match string. 1357 * @param replacement 1358 * Replacement string. 1359 * @param wrkSpace 1360 * Work space - simply to reduce object creation per invocation. 1361 * @return Source string with all occurances of the match string replaced by 1362 * the replacement string. 1363 */ 1364 private static String substitute(String source, String match, 1365 String replacement, StringBuffer wrkSpace) 1366 { 1367 // Wipe out work buffer 1368 wrkSpace.setLength(0); 1369 1370 int subjectLen = source.length(); 1371 int matchLen = match.length(); 1372 for (int beginIndex = 0; beginIndex < subjectLen;) 1373 { 1374 int matchStartIndex = source.indexOf(match, beginIndex); 1375 if (matchStartIndex >= 0) 1376 { 1377 wrkSpace.append(source.substring(beginIndex, matchStartIndex)) 1378 .append(replacement); 1379 beginIndex = matchStartIndex + matchLen; 1380 } 1381 else 1382 { 1383 wrkSpace.append(source.substring(beginIndex)); 1384 break; 1385 } 1386 } 1387 1388 return wrkSpace.toString(); 1389 } 1390 1391 /*** 1392 * Get message specification version. 1393 * 1394 * @return Message specification version number. If version is not defined, 1395 * returns <tt>null</tt>. 1396 */ 1397 public final String getMsgVersion() 1398 { 1399 return version_; 1400 } 1401 1402 /*** 1403 * Set message specification version number. 1404 * 1405 * @param version 1406 * Message specification version number. 1407 */ 1408 protected final void setMsgVersion(String version) 1409 { 1410 version_ = version; 1411 } 1412 1413 /*** 1414 * Get the value of a field. A reference to the data is returned so be 1415 * careful about modifying the data through the reference. For fields nested 1416 * within RFldTibrvMsg (TibrvMsg) fields the name can be a dot notation 1417 * field name. 1418 * 1419 * @param fldName 1420 * Field name. 1421 * @return Field value. 1422 * @see RFld 1423 * @see RFldTibrvMsg#getValueAsObject(String, String) 1424 */ 1425 public final Object getFieldValueAsObject(String fldName) 1426 throws FieldValidationException 1427 { 1428 // If a non-nested field exists with the specified name, simply return 1429 // it. 1430 // Otherwise, attempt to find a nested field with the specified name. 1431 if (fieldExists(fldName)) 1432 return getField(fldName).getValueAsObject(); 1433 1434 return getNestedFieldValueAsObject(fldName); 1435 } 1436 1437 /*** 1438 * Get the value of a field. A reference to the data is returned so be 1439 * careful about modifying the data through the reference. 1440 * 1441 * @param fldName 1442 * Field name. 1443 * @return Field value. 1444 * @see RFld 1445 */ 1446 protected final Object getNestedFieldValueAsObject(String fldName) 1447 throws FieldValidationException 1448 { 1449 int beginIndex = fldName.indexOf(NESTED_FIELDNAME_DELIMITER); 1450 1451 // Get the top-level container field 1452 String containerFldName = null; 1453 if (beginIndex >= 0) 1454 containerFldName = fldName.substring(0, beginIndex); 1455 1456 if (containerFldName == null) 1457 throw new FieldValidationException("Field not found: " + fldName); 1458 1459 RFld containerFld = getField(containerFldName); 1460 if (!(containerFld instanceof RFldTibrvMsg)) 1461 throw new FieldValidationException("Invalid field type: " + fldName); 1462 1463 RFldTibrvMsg msgFld = (RFldTibrvMsg) containerFld; 1464 return msgFld.getValueAsObject(fldName.substring(beginIndex + 1), 1465 NESTED_FIELDNAME_DELIMITER); 1466 } 1467 1468 /*** 1469 * Get field value as string. 1470 * 1471 * @param fldName 1472 * Field name. 1473 * @return Field value. 1474 */ 1475 public final String getFieldValueAsString(String fldName) 1476 throws FieldValidationException 1477 { 1478 Object fldVal = getFieldValueAsObject(fldName); 1479 return (fldVal != null) ? fldVal.toString() : null; 1480 } 1481 1482 /*** 1483 * Get the value of a <tt>TibrvMsg</tt> field. A reference to the data is 1484 * returned so be careful about modifying the data through the reference. 1485 * 1486 * @param fldName 1487 * Field name. 1488 * @return Field value. 1489 * @see RFldTibrvMsg 1490 */ 1491 public final Object getTibrvMsg(String fldName) 1492 throws FieldValidationException 1493 { 1494 try 1495 { 1496 RFld fld = getField(fldName); 1497 return ((RFldTibrvMsg) fld).getValue(); 1498 } 1499 catch (java.lang.ClassCastException ex) 1500 { 1501 throw new FieldValidationException("Field type mismatch: " 1502 + fldName); 1503 } 1504 } 1505 1506 /*** 1507 * Get the value of a Opaque field. A reference to the data is returned so 1508 * be careful about modifying the data through the reference. 1509 * 1510 * @param fldName 1511 * Field name. 1512 * @return Field value. 1513 * @see RFldOpaque 1514 */ 1515 public final byte[] getOpaque(String fldName) 1516 throws FieldValidationException 1517 { 1518 try 1519 { 1520 RFld fld = getField(fldName); 1521 return ((RFldOpaque) fld).getValue(); 1522 } 1523 catch (java.lang.ClassCastException ex) 1524 { 1525 throw new FieldValidationException("Field type mismatch: " 1526 + fldName); 1527 } 1528 } 1529 1530 /*** 1531 * Get the value of a datetime field. A reference to the data is returned so 1532 * be careful about modifying the data through the reference. 1533 * 1534 * @param fldName 1535 * Field name. 1536 * @return Field value. 1537 * @see RFldDatetime 1538 */ 1539 public final java.util.Date getDate(String fldName) 1540 throws FieldValidationException 1541 { 1542 try 1543 { 1544 RFld fld = getField(fldName); 1545 return ((RFldDatetime) fld).getValue(); 1546 } 1547 catch (java.lang.ClassCastException ex) 1548 { 1549 throw new FieldValidationException("Field type mismatch: " 1550 + fldName); 1551 } 1552 } 1553 1554 /*** 1555 * Get the value of a boolean field. 1556 * 1557 * @param fldName 1558 * Field name. 1559 * @return Field value. 1560 * @see RFldBool 1561 */ 1562 public final boolean getBoolean(String fldName) 1563 throws FieldValidationException 1564 { 1565 try 1566 { 1567 RFld fld = getField(fldName); 1568 return ((RFldBool) fld).getValue(); 1569 } 1570 catch (java.lang.ClassCastException ex) 1571 { 1572 throw new FieldValidationException("Field type mismatch: " 1573 + fldName); 1574 } 1575 } 1576 1577 /*** 1578 * Get the value of a opaque field. A reference to the data is returned so 1579 * be careful about modifying the data through the reference. 1580 * 1581 * @param fldName 1582 * Field name. 1583 * @return Field value. 1584 * @see RFldOpaque 1585 */ 1586 public final byte[] getBytes(String fldName) 1587 throws FieldValidationException 1588 { 1589 try 1590 { 1591 RFld fld = getField(fldName); 1592 return ((RFldOpaque) fld).getValue(); 1593 } 1594 catch (java.lang.ClassCastException ex) 1595 { 1596 throw new FieldValidationException("Field type mismatch: " 1597 + fldName); 1598 } 1599 } 1600 1601 /*** 1602 * Get the value of a float field. 1603 * 1604 * @param fldName 1605 * Field name. 1606 * @return Field value. 1607 * @see RFldF32 1608 */ 1609 public final float getFloat(String fldName) throws FieldValidationException 1610 { 1611 try 1612 { 1613 RFld fld = getField(fldName); 1614 return ((RFldF32) fld).getValue(); 1615 } 1616 catch (java.lang.ClassCastException ex) 1617 { 1618 throw new FieldValidationException("Field type mismatch: " 1619 + fldName); 1620 } 1621 } 1622 1623 /*** 1624 * Get the value of a double field. 1625 * 1626 * @param fldName 1627 * Field name. 1628 * @return Field value. 1629 * @see RFldF64 1630 */ 1631 public final double getDouble(String fldName) 1632 throws FieldValidationException 1633 { 1634 try 1635 { 1636 RFld fld = getField(fldName); 1637 return ((RFldF64) fld).getValue(); 1638 } 1639 catch (java.lang.ClassCastException ex) 1640 { 1641 throw new FieldValidationException("Field type mismatch: " 1642 + fldName); 1643 } 1644 } 1645 1646 /*** 1647 * Get the value of a byte field. 1648 * 1649 * @param fldName 1650 * Field name. 1651 * @return Field value. 1652 * @see RFldI8 1653 */ 1654 public final byte getByte(String fldName) throws FieldValidationException 1655 { 1656 try 1657 { 1658 RFld fld = getField(fldName); 1659 return ((RFldI8) fld).getValue(); 1660 } 1661 catch (java.lang.ClassCastException ex) 1662 { 1663 throw new FieldValidationException("Field type mismatch: " 1664 + fldName); 1665 } 1666 } 1667 1668 /*** 1669 * Get the value of a short field. 1670 * 1671 * @param fldName 1672 * Field name. 1673 * @return Field value. 1674 * @see RFldI16 1675 */ 1676 public final short getShort(String fldName) throws FieldValidationException 1677 { 1678 try 1679 { 1680 RFld fld = getField(fldName); 1681 return ((RFldI16) fld).getValue(); 1682 } 1683 catch (java.lang.ClassCastException ex) 1684 { 1685 throw new FieldValidationException("Field type mismatch: " 1686 + fldName); 1687 } 1688 } 1689 1690 /*** 1691 * Get the value of a integer field. 1692 * 1693 * @param fldName 1694 * Field name. 1695 * @return Field value. 1696 * @see RFldI32 1697 */ 1698 public final int getInt(String fldName) throws FieldValidationException 1699 { 1700 try 1701 { 1702 RFld fld = getField(fldName); 1703 return ((RFldI32) fld).getValue(); 1704 } 1705 catch (java.lang.ClassCastException ex) 1706 { 1707 throw new FieldValidationException("Field type mismatch: " 1708 + fldName); 1709 } 1710 } 1711 1712 /*** 1713 * Get the value of a long field. 1714 * 1715 * @param fldName 1716 * Field name. 1717 * @return Field value. 1718 * @see RFldI64 1719 */ 1720 public final long getLong(String fldName) throws FieldValidationException 1721 { 1722 try 1723 { 1724 RFld fld = getField(fldName); 1725 return ((RFldI64) fld).getValue(); 1726 } 1727 catch (java.lang.ClassCastException ex) 1728 { 1729 throw new FieldValidationException("Field type mismatch: " 1730 + fldName); 1731 } 1732 } 1733 1734 /*** 1735 * Get the value of a bean field. 1736 * 1737 * @param fldName 1738 * Field name. 1739 * @return Field value. 1740 * @see RFldBean 1741 */ 1742 public final Object getBean(String fldName) throws FieldValidationException 1743 { 1744 try 1745 { 1746 RFld fld = getField(fldName); 1747 return ((RFldBean) fld).getValue(); 1748 } 1749 catch (java.lang.ClassCastException ex) 1750 { 1751 throw new FieldValidationException("Field type mismatch: " 1752 + fldName); 1753 } 1754 } 1755 1756 /*** 1757 * Get the value of a string field. 1758 * 1759 * @param fldName 1760 * Field name. 1761 * @return Field value. 1762 * @see RFldString 1763 */ 1764 public final String getString(String fldName) 1765 throws FieldValidationException 1766 { 1767 try 1768 { 1769 RFld fld = getField(fldName); 1770 return ((RFldString) fld).getValue(); 1771 } 1772 catch (java.lang.ClassCastException ex) 1773 { 1774 throw new FieldValidationException("Field type mismatch: " 1775 + fldName); 1776 } 1777 } 1778 1779 /*** 1780 * Get the value of a memo field. 1781 * 1782 * @param fldName 1783 * Field name. 1784 * @return Field value. 1785 * @see RFldMemo 1786 */ 1787 public final String getMemo(String fldName) throws FieldValidationException 1788 { 1789 try 1790 { 1791 RFld fld = getField(fldName); 1792 return ((RFldMemo) fld).getValue(); 1793 } 1794 catch (java.lang.ClassCastException ex) 1795 { 1796 throw new FieldValidationException("Field type mismatch: " 1797 + fldName); 1798 } 1799 } 1800 1801 /*** 1802 * Add a TibrvMsg field. 1803 * 1804 * @param fldName 1805 * Field name. 1806 * @param fieldId 1807 * Field Id. <tt>0</tt> means the field has no id. 1808 * @param fldDesc 1809 * Field description. Can be <tt>null</tt>. 1810 * @see RFldTibrvMsg 1811 */ 1812 public final void addMsg(String fldName, int fieldId, String fldDesc) 1813 throws FieldValidationException 1814 { 1815 if (fieldId < 0) 1816 throw new FieldValidationException( 1817 "Field Id must be greater or equal to 0"); 1818 1819 addField(new RFldTibrvMsg(fldName, fieldId, fldDesc)); 1820 } 1821 1822 /*** 1823 * Add an Opaque field. 1824 * 1825 * @param fldName 1826 * Field name. 1827 * @param fieldId 1828 * Field Id. <tt>0</tt> means the field has no id. 1829 * @param fldDesc 1830 * Field description. Can be <tt>null</tt>. 1831 * @see RFldOpaque 1832 */ 1833 public final void addOpaque(String fldName, int fieldId, String fldDesc) 1834 throws FieldValidationException 1835 { 1836 if (fieldId < 0) 1837 throw new FieldValidationException( 1838 "Field Id must be greater or equal to 0"); 1839 1840 addField(new RFldOpaque(fldName, fieldId, fldDesc)); 1841 } 1842 1843 /*** 1844 * GAdd a datetime field. 1845 * 1846 * @param fldName 1847 * Field name. 1848 * @param fieldId 1849 * Field Id. <tt>0</tt> means the field has no id. 1850 * @param fldDesc 1851 * Field description. Can be <tt>null</tt>. 1852 * @see RFldDatetime 1853 */ 1854 public final void addDate(String fldName, int fieldId, String fldDesc) 1855 throws FieldValidationException 1856 { 1857 if (fieldId < 0) 1858 throw new FieldValidationException( 1859 "Field Id must be greater or equal to 0"); 1860 1861 addField(new RFldDatetime(fldName, fieldId, fldDesc)); 1862 } 1863 1864 /*** 1865 * Add a boolean field. 1866 * 1867 * @param fldName 1868 * Field name. 1869 * @param fieldId 1870 * Field Id. <tt>0</tt> means the field has no id. 1871 * @param fldDesc 1872 * Field description. Can be <tt>null</tt>. 1873 * @see RFldBool 1874 */ 1875 public final void addBoolean(String fldName, int fieldId, String fldDesc) 1876 throws FieldValidationException 1877 { 1878 if (fieldId < 0) 1879 throw new FieldValidationException( 1880 "Field Id must be greater or equal to 0"); 1881 1882 addField(new RFldBool(fldName, fieldId, fldDesc)); 1883 } 1884 1885 /*** 1886 * Add a float field. 1887 * 1888 * @param fldName 1889 * Field name. 1890 * @param fieldId 1891 * Field Id. <tt>0</tt> means the field has no id. 1892 * @param fldDesc 1893 * Field description. Can be <tt>null</tt>. 1894 * @see RFldF32 1895 */ 1896 public final void addFloat(String fldName, int fieldId, String fldDesc) 1897 throws FieldValidationException 1898 { 1899 if (fieldId < 0) 1900 throw new FieldValidationException( 1901 "Field Id must be greater or equal to 0"); 1902 1903 addField(new RFldF32(fldName, fieldId, fldDesc)); 1904 } 1905 1906 /*** 1907 * Add a double field. 1908 * 1909 * @param fldName 1910 * Field name. 1911 * @param fieldId 1912 * Field Id. <tt>0</tt> means the field has no id. 1913 * @param fldDesc 1914 * Field description. Can be <tt>null</tt>. 1915 * @see RFldF64 1916 */ 1917 public final void addDouble(String fldName, int fieldId, String fldDesc) 1918 throws FieldValidationException 1919 { 1920 if (fieldId < 0) 1921 throw new FieldValidationException( 1922 "Field Id must be greater or equal to 0"); 1923 1924 addField(new RFldF64(fldName, fieldId, fldDesc)); 1925 } 1926 1927 /*** 1928 * Add a short field. 1929 * 1930 * @param fldName 1931 * Field name. 1932 * @param fieldId 1933 * Field Id. <tt>0</tt> means the field has no id. 1934 * @param fldDesc 1935 * Field description. Can be <tt>null</tt>. 1936 * @see RFldI16 1937 */ 1938 public final void addShort(String fldName, int fieldId, String fldDesc) 1939 throws FieldValidationException 1940 { 1941 if (fieldId < 0) 1942 throw new FieldValidationException( 1943 "Field Id must be greater or equal to 0"); 1944 1945 addField(new RFldI16(fldName, fieldId, fldDesc)); 1946 } 1947 1948 /*** 1949 * Add an integer field. 1950 * 1951 * @param fldName 1952 * Field name. 1953 * @param fieldId 1954 * Field Id. <tt>0</tt> means the field has no id. 1955 * @param fldDesc 1956 * Field description. Can be <tt>null</tt>. 1957 * @see RFldI32 1958 */ 1959 public final void addInt(String fldName, int fieldId, String fldDesc) 1960 throws FieldValidationException 1961 { 1962 if (fieldId < 0) 1963 throw new FieldValidationException( 1964 "Field Id must be greater or equal to 0"); 1965 1966 addField(new RFldI32(fldName, fieldId, fldDesc)); 1967 } 1968 1969 /*** 1970 * Get the value of a long field. 1971 * 1972 * @param fldName 1973 * Field name. 1974 * @param fieldId 1975 * Field Id. <tt>0</tt> means the field has no id. 1976 * @param fldDesc 1977 * Field description. Can be <tt>null</tt>. 1978 * @see RFldI64 1979 */ 1980 public final void addLong(String fldName, int fieldId, String fldDesc) 1981 throws FieldValidationException 1982 { 1983 if (fieldId < 0) 1984 throw new FieldValidationException( 1985 "Field Id must be greater or equal to 0"); 1986 1987 addField(new RFldI64(fldName, fieldId, fldDesc)); 1988 } 1989 1990 /*** 1991 * Add a string field. 1992 * 1993 * @param fldName 1994 * Field name. 1995 * @param fieldId 1996 * Field Id. <tt>0</tt> means the field has no id. 1997 * @param fldDesc 1998 * Field description. Can be <tt>null</tt>. 1999 * @see RFldString 2000 */ 2001 public final void addString(String fldName, int fieldId, String fldDesc) 2002 throws FieldValidationException 2003 { 2004 if (fieldId < 0) 2005 throw new FieldValidationException( 2006 "Field Id must be greater or equal to 0"); 2007 2008 addField(new RFldString(fldName, fieldId, fldDesc)); 2009 } 2010 2011 /*** 2012 * Add a memo field. 2013 * 2014 * @param fldName 2015 * Field name. 2016 * @param fieldId 2017 * Field Id. <tt>0</tt> means the field has no id. 2018 * @param fldDesc 2019 * Field description. Can be <tt>null</tt>. 2020 * @see RFldMemo 2021 */ 2022 public final void addMemo(String fldName, int fieldId, String fldDesc) 2023 throws FieldValidationException 2024 { 2025 if (fieldId < 0) 2026 throw new FieldValidationException( 2027 "Field Id must be greater or equal to 0"); 2028 2029 addField(new RFldMemo(fldName, fieldId, fldDesc)); 2030 } 2031 2032 /*** 2033 * Set the value of a TibrvMsg field. 2034 * 2035 * @param fldName 2036 * Field name. 2037 * @param val 2038 * Field value. 2039 * @see RFldTibrvMsg 2040 */ 2041 public final void setTibrvMsg(String fldName, Object val) 2042 throws FieldValidationException 2043 { 2044 if (isLocked()) 2045 throw new FieldValidationException("Message is locked"); 2046 2047 try 2048 { 2049 RFld fld = getField(fldName); 2050 fld.set(val); 2051 } 2052 catch (java.lang.ClassCastException ex) 2053 { 2054 throw new FieldValidationException("Field type mismatch: " 2055 + fldName); 2056 } 2057 } 2058 2059 /*** 2060 * Set the value of a Opaque field. 2061 * 2062 * @param fldName 2063 * Field name. 2064 * @param val 2065 * Field value. 2066 * @see RFldOpaque 2067 */ 2068 public final void setOpaque(String fldName, byte[] val) 2069 throws FieldValidationException 2070 { 2071 if (isLocked()) 2072 throw new FieldValidationException("Message is locked"); 2073 2074 try 2075 { 2076 RFld fld = getField(fldName); 2077 ((RFldOpaque) fld).set(val); 2078 } 2079 catch (java.lang.ClassCastException ex) 2080 { 2081 throw new FieldValidationException("Field type mismatch: " 2082 + fldName); 2083 } 2084 } 2085 2086 /*** 2087 * Get the value of a datetime field. 2088 * 2089 * @param fldName 2090 * Field name. 2091 * @param val 2092 * value. 2093 * @see RFldDatetime 2094 */ 2095 public final void setDate(String fldName, java.util.Date val) 2096 throws FieldValidationException 2097 { 2098 if (isLocked()) 2099 throw new FieldValidationException("Message is locked"); 2100 try 2101 { 2102 RFld fld = getField(fldName); 2103 ((RFldDatetime) fld).set(val); 2104 } 2105 catch (java.lang.ClassCastException ex) 2106 { 2107 throw new FieldValidationException("Field type mismatch: " 2108 + fldName); 2109 } 2110 } 2111 2112 /*** 2113 * Get the value of a datetime field. 2114 * 2115 * @param fldName 2116 * Field name. 2117 * @param val 2118 * value. 2119 * @see RFldDatetime 2120 */ 2121 public final void setDate(String fldName, long val) 2122 throws FieldValidationException 2123 { 2124 if (isLocked()) 2125 throw new FieldValidationException("Message is locked"); 2126 2127 try 2128 { 2129 RFld fld = getField(fldName); 2130 ((RFldDatetime) fld).set(val); 2131 } 2132 catch (java.lang.ClassCastException ex) 2133 { 2134 throw new FieldValidationException("Field type mismatch: " 2135 + fldName); 2136 } 2137 } 2138 2139 /*** 2140 * Get the value of a boolean field. 2141 * 2142 * @param fldName 2143 * Field name. 2144 * @param val 2145 * Field value. 2146 * @see RFldBool 2147 */ 2148 public final void setBoolean(String fldName, boolean val) 2149 throws FieldValidationException 2150 { 2151 if (isLocked()) 2152 throw new FieldValidationException("Message is locked"); 2153 2154 try 2155 { 2156 RFld fld = getField(fldName); 2157 ((RFldBool) fld).set(val); 2158 } 2159 catch (java.lang.ClassCastException ex) 2160 { 2161 throw new FieldValidationException("Field type mismatch: " 2162 + fldName); 2163 } 2164 } 2165 2166 /*** 2167 * Get the value of a opaque field. 2168 * 2169 * @param fldName 2170 * Field name. 2171 * @param val 2172 * Field value. 2173 * @see RFldOpaque 2174 */ 2175 public final void setBytes(String fldName, byte[] val) 2176 throws FieldValidationException 2177 { 2178 if (isLocked()) 2179 throw new FieldValidationException("Message is locked"); 2180 2181 try 2182 { 2183 RFld fld = getField(fldName); 2184 ((RFldOpaque) fld).set(val); 2185 } 2186 catch (java.lang.ClassCastException ex) 2187 { 2188 throw new FieldValidationException("Field type mismatch: " 2189 + fldName); 2190 } 2191 } 2192 2193 /*** 2194 * Set the value of a float field. 2195 * 2196 * @param fldName 2197 * Field name. 2198 * @param val 2199 * Field value. 2200 * @see RFldF32 2201 */ 2202 public final void setFloat(String fldName, float val) 2203 throws FieldValidationException 2204 { 2205 if (isLocked()) 2206 throw new FieldValidationException("Message is locked"); 2207 2208 try 2209 { 2210 RFld fld = getField(fldName); 2211 ((RFldF32) fld).set(val); 2212 } 2213 catch (java.lang.ClassCastException ex) 2214 { 2215 throw new FieldValidationException("Field type mismatch: " 2216 + fldName); 2217 } 2218 } 2219 2220 /*** 2221 * Set the value of a double field. 2222 * 2223 * @param fldName 2224 * Field name. 2225 * @param val 2226 * Field value. 2227 * @see RFldF64 2228 */ 2229 public final void setDouble(String fldName, double val) 2230 throws FieldValidationException 2231 { 2232 if (isLocked()) 2233 throw new FieldValidationException("Message is locked"); 2234 2235 try 2236 { 2237 RFld fld = getField(fldName); 2238 ((RFldF64) fld).set(val); 2239 } 2240 catch (java.lang.ClassCastException ex) 2241 { 2242 throw new FieldValidationException("Field type mismatch: " 2243 + fldName); 2244 } 2245 } 2246 2247 /*** 2248 * Set the value of a byte field. 2249 * 2250 * @param fldName 2251 * Field name. 2252 * @param val 2253 * Field value. 2254 * @see RFldI8 2255 */ 2256 public final void setByte(String fldName, byte val) 2257 throws FieldValidationException 2258 { 2259 if (isLocked()) 2260 throw new FieldValidationException("Message is locked"); 2261 2262 try 2263 { 2264 RFld fld = getField(fldName); 2265 ((RFldI8) fld).set(val); 2266 } 2267 catch (java.lang.ClassCastException ex) 2268 { 2269 throw new FieldValidationException("Field type mismatch: " 2270 + fldName); 2271 } 2272 } 2273 2274 /*** 2275 * Set the value of a short field. 2276 * 2277 * @param fldName 2278 * Field name. 2279 * @param val 2280 * Field value. 2281 * @see RFldI16 2282 */ 2283 public final void setShort(String fldName, short val) 2284 throws FieldValidationException 2285 { 2286 if (isLocked()) 2287 throw new FieldValidationException("Message is locked"); 2288 2289 try 2290 { 2291 RFld fld = getField(fldName); 2292 ((RFldI16) fld).set(val); 2293 } 2294 catch (java.lang.ClassCastException ex) 2295 { 2296 throw new FieldValidationException("Field type mismatch: " 2297 + fldName); 2298 } 2299 } 2300 2301 /*** 2302 * Set the value of a integer field. 2303 * 2304 * @param fldName 2305 * Field name. 2306 * @param val 2307 * Field value. 2308 * @see RFldI32 2309 */ 2310 public final void setInt(String fldName, int val) 2311 throws FieldValidationException 2312 { 2313 if (isLocked()) 2314 throw new FieldValidationException("Message is locked"); 2315 2316 try 2317 { 2318 RFld fld = getField(fldName); 2319 ((RFldI32) fld).set(val); 2320 } 2321 catch (java.lang.ClassCastException ex) 2322 { 2323 throw new FieldValidationException("Field type mismatch: " 2324 + fldName); 2325 } 2326 } 2327 2328 /*** 2329 * Set the value of a long field. 2330 * 2331 * @param fldName 2332 * Field name. 2333 * @param val 2334 * Field value. 2335 * @see RFldI64 2336 */ 2337 public final void setLong(String fldName, long val) 2338 throws FieldValidationException 2339 { 2340 if (isLocked()) 2341 throw new FieldValidationException("Message is locked"); 2342 2343 try 2344 { 2345 RFld fld = getField(fldName); 2346 ((RFldI64) fld).set(val); 2347 } 2348 catch (java.lang.ClassCastException ex) 2349 { 2350 throw new FieldValidationException("Field type mismatch: " 2351 + fldName); 2352 } 2353 } 2354 2355 /*** 2356 * Set the value of a field from an object. 2357 * 2358 * @param fldName 2359 * Field name. 2360 * @param val 2361 * Field value. 2362 * @see RFld 2363 */ 2364 public final void setFieldFromObject(String fldName, Object val) 2365 throws FieldValidationException 2366 { 2367 getField(fldName).set(val); 2368 } 2369 2370 /*** 2371 * Set the value of a bean field. 2372 * 2373 * @param fldName 2374 * Field name. 2375 * @param val 2376 * Field value. 2377 * @see RFldString 2378 */ 2379 public final void setBean(String fldName, Object val) 2380 throws FieldValidationException 2381 { 2382 if (isLocked()) 2383 throw new FieldValidationException("Message is locked"); 2384 2385 try 2386 { 2387 RFld fld = getField(fldName); 2388 ((RFldBean) fld).set(val); 2389 } 2390 catch (java.lang.ClassCastException ex) 2391 { 2392 throw new FieldValidationException("Field type mismatch: " 2393 + fldName); 2394 } 2395 } 2396 2397 /*** 2398 * Set the value of a string field. 2399 * 2400 * @param fldName 2401 * Field name. 2402 * @param val 2403 * Field value. 2404 * @see RFldString 2405 */ 2406 public final void setString(String fldName, String val) 2407 throws FieldValidationException 2408 { 2409 if (isLocked()) 2410 throw new FieldValidationException("Message is locked"); 2411 2412 try 2413 { 2414 RFld fld = getField(fldName); 2415 ((RFldString) fld).set(val); 2416 } 2417 catch (java.lang.ClassCastException ex) 2418 { 2419 throw new FieldValidationException("Field type mismatch: " 2420 + fldName); 2421 } 2422 } 2423 2424 /*** 2425 * Set the value of a memo field. 2426 * 2427 * @param fldName 2428 * Field name. 2429 * @param val 2430 * Field value. 2431 * @see RFldMemo 2432 */ 2433 public final void setMemo(String fldName, String val) 2434 throws FieldValidationException 2435 { 2436 if (isLocked()) 2437 throw new FieldValidationException("Message is locked"); 2438 2439 try 2440 { 2441 RFld fld = getField(fldName); 2442 ((RFldMemo) fld).set(val); 2443 } 2444 catch (java.lang.ClassCastException ex) 2445 { 2446 throw new FieldValidationException("Field type mismatch: " 2447 + fldName); 2448 } 2449 } 2450 2451 /*** 2452 * Check if a named field exists in this message. Either there is an exact 2453 * match for the field name, or, case-insentitive names are enabled and 2454 * there is a case-insensitive field name match. 2455 * 2456 * @param fldName 2457 * Field name. 2458 * @return <tt>true</tt> if the named field exists. Otherwise returns 2459 * <tt>false</tt>. 2460 */ 2461 public final boolean fieldExists(String fldName) 2462 { 2463 // Either there is an exact match for the field name, or, 2464 // case-insentitive 2465 // names are enabled and there is a case-insensitive match. 2466 return (flds_.containsKey(fldName) || (noCaseFlds_ != null && noCaseFlds_ 2467 .containsKey(fldName.toUpperCase()))); 2468 } 2469 2470 /*** 2471 * Determine if the value of a named message field has been set. 2472 * 2473 * @param fldName 2474 * Field name. 2475 * @return <tt>true</tt> if the value of a named message field has been 2476 * set. Otherwise, returns <tt>false</tt>. 2477 */ 2478 public final boolean isValSet(String fldName) 2479 throws FieldValidationException 2480 { 2481 return getField(fldName).isValSet(); 2482 } 2483 2484 /*** 2485 * Determine if the value of a named message has any constraints. 2486 * 2487 * @param fldName 2488 * Field name. 2489 * @return <tt>true</tt> if the value of a named message field has been 2490 * constrained. Otherwise, returns <tt>false</tt>. 2491 */ 2492 public final boolean isConstrained(String fldName) 2493 throws FieldValidationException 2494 { 2495 return getField(fldName).isConstrained(); 2496 } 2497 2498 /*** 2499 * Determine if a named message field is locked. 2500 * 2501 * @param fldName 2502 * Field name. 2503 * @return <tt>true</tt> if the named field is locked. Otherwise, returns 2504 * <tt>false</tt>. 2505 */ 2506 public final boolean isLocked(String fldName) 2507 throws FieldValidationException 2508 { 2509 return getField(fldName).isLocked(); 2510 } 2511 2512 /*** 2513 * Get the number of fields in this message. 2514 * 2515 * @return Number of fields in this message. 2516 */ 2517 public final int getFieldCount() 2518 { 2519 return flds_.size(); 2520 } 2521 2522 /*** 2523 * Get all names of all fields in the message. 2524 * 2525 * @return Iterator over all field names in the message. 2526 */ 2527 public final java.util.Iterator getFieldNames() 2528 { 2529 return flds_.keySet().iterator(); 2530 } 2531 2532 /*** 2533 * Check if this is an empty message. An empty message is one that has not 2534 * been defined externally via XML. These empty messages have their fields 2535 * added dynamically by the application at run-time. 2536 * 2537 * @return <tt>true</tt> if this is an empty message. Otherwise returns 2538 * <tt>false</tt>. 2539 * @see #setEmptyMsg(boolean) 2540 */ 2541 public final boolean isEmptyMsg() 2542 { 2543 return emptyMsg_; 2544 } 2545 2546 /*** 2547 * Set the <tt>empty</tt> attribute of this message. 2548 * 2549 * @param emptyMsg 2550 * <tt>true</tt> if this is an empty message. Otherwise 2551 * <tt>false</tt>. 2552 * @see #isEmptyMsg() 2553 */ 2554 public final void setEmptyMsg(boolean emptyMsg) 2555 { 2556 emptyMsg_ = emptyMsg; 2557 } 2558 2559 /*** 2560 * Set the case-insensitive field name option. 2561 * 2562 * @param val 2563 * If <tt>true</tt> then the framework allows field names to be 2564 * accessed in a case-insensitive manner. Otherwise, field names 2565 * are case sensitive. 2566 * @see#getField(String) 2567 * @see#fieldExists(String) 2568 */ 2569 public static final void supportNoCaseFldNames(boolean val) 2570 { 2571 noCaseFldNames_ = val; 2572 } 2573 2574 /*** 2575 * Register custom XML field tag. 2576 * 2577 * @param newTag 2578 * New XML field tag. 2579 */ 2580 public static final void setXmlTag(String newTag) 2581 throws FieldValidationException 2582 { 2583 if (newTag == null) 2584 throw new FieldValidationException("NULL tag"); 2585 2586 XML_TAG = newTag; 2587 } 2588 2589 /*** 2590 * Register custom XML attribute names. 2591 * 2592 * @param name 2593 * New name of the message name attribute. 2594 */ 2595 public static final void setXmlAttrNames(String name) 2596 throws FieldValidationException 2597 { 2598 if (name == null) 2599 throw new FieldValidationException("NULL attribute name"); 2600 2601 XML_ATTR_NAME = name; 2602 } 2603 2604 /*** 2605 * Get 'pretty print' string representation of message contents. 2606 * 2607 * @return Pretty print String representation of message contents. 2608 */ 2609 public String toPrettyPrintString() 2610 { 2611 int indentLevel = 0; 2612 String str = toString(); 2613 int len = str.length(); 2614 StringBuffer sb = new StringBuffer(len + (len / 80) + 20); 2615 for (int i = 0; i < len;) 2616 { 2617 if (str.charAt(i) == NESTED_FIELD_START) 2618 { 2619 sb.append('\n'); 2620 indent(sb, indentLevel); 2621 2622 sb.append(NESTED_FIELD_START); 2623 2624 ++indentLevel; 2625 2626 ++i; 2627 } 2628 else if (str.charAt(i) == NESTED_FIELD_END) 2629 { 2630 sb.append('\n'); 2631 --indentLevel; 2632 2633 indent(sb, indentLevel); 2634 sb.append(NESTED_FIELD_END); 2635 2636 ++i; 2637 } 2638 else if (str.charAt(i) == EXPOSED_FIELD_DELIMITER) 2639 { 2640 ++i; 2641 } 2642 else 2643 { 2644 sb.append('\n'); 2645 indent(sb, indentLevel); 2646 2647 // Insert field name/contents 2648 char c = str.charAt(i); 2649 while (c != EXPOSED_FIELD_DELIMITER && c != NESTED_FIELD_START 2650 && c != NESTED_FIELD_END) 2651 { 2652 sb.append(c); 2653 2654 ++i; 2655 if (i >= len) 2656 break; 2657 2658 c = str.charAt(i); 2659 } 2660 } 2661 } 2662 return sb.toString(); 2663 } 2664 2665 /*** 2666 * Insert indentation into a string buffer. 2667 * 2668 * @param sb 2669 * String buffer. 2670 * @param indentLevel 2671 * Indentation level. 2672 */ 2673 private final void indent(StringBuffer sb, int indentLevel) 2674 { 2675 // Indent - 4 spaces per indent level 2676 for (int j = 0; j < indentLevel; ++j) 2677 sb.append(" "); 2678 } 2679 2680 /*** 2681 * Get string representation of message contents. 2682 * 2683 * @return String representation of message contents. 2684 */ 2685 public String toString() 2686 { 2687 StringBuffer sb = new StringBuffer(128); 2688 sb.append(NESTED_FIELD_START); 2689 2690 boolean notFirst = false; 2691 RFld[] fldsArray = getFieldsAsArray(); 2692 for (int i = fldsArray.length - 1; i >= 0; --i) 2693 { 2694 RFld fld = fldsArray[i]; 2695 if (notFirst) 2696 sb.append(EXPOSED_FIELD_DELIMITER); 2697 else 2698 notFirst = true; 2699 2700 if (fld.isValSet()) 2701 sb.append(fld.getName()).append(FIELD_EQUAL).append( 2702 fld.getValueAsString()); 2703 else 2704 sb.append(fld.getName()).append(FIELD_EQUAL).append(NA_VALUE); 2705 } 2706 sb.append(NESTED_FIELD_END); 2707 return sb.toString(); 2708 } 2709 2710 /*** 2711 * Check if another message is equal to this message. Equality is defined as 2712 * both messages having the same fields (name, type), and all fields having 2713 * the same, non-null, value. 2714 * 2715 * @param anObject 2716 * Another message. 2717 * @return <tt>true</tt> if another message is equal to this message. 2718 * Otherwise, returns <tt>false</tt>. 2719 */ 2720 public boolean equals(Object anObject) 2721 { 2722 // Sanity checks 2723 if (this == anObject) 2724 return true; 2725 else if (!(anObject instanceof RMsg)) 2726 return false; 2727 2728 // Compare number of fields - quick check to compare messages 2729 RMsg anotherMsg = (RMsg) anObject; 2730 if (getFieldCount() != anotherMsg.getFieldCount()) 2731 return false; 2732 2733 // Compare each field 2734 RFld[] fldsArray = getFieldsAsArray(); 2735 for (int i = fldsArray.length - 1; i >= 0; --i) 2736 { 2737 try 2738 { 2739 RFld fld = fldsArray[i]; 2740 String fldName = fld.getName(); 2741 if (!anotherMsg.fieldExists(fldName)) 2742 return false; 2743 2744 boolean fldValSet = fld.isValSet(); 2745 2746 RFld anotherFld = anotherMsg.getField(fldName); 2747 boolean anotherFldValSet = anotherFld.isValSet(); 2748 2749 // Skip this field if it is set in neither message 2750 if (!fldValSet && !anotherFldValSet) 2751 continue; 2752 // If this field is not set in ONE of the messages, or if the 2753 // field values 2754 // are not equal in the two messages, then the messages are not 2755 // equal 2756 else if ((fldValSet != anotherFldValSet) 2757 || (!fld.equals(anotherFld))) 2758 return false; 2759 } 2760 catch (FieldValidationException ex) 2761 { 2762 return false; 2763 } 2764 } 2765 return true; 2766 } 2767 2768 /*** 2769 * Check if another message is equal to this message. Equality is defined in 2770 * the same way as for <tt>equals</tt> except for the following: only the 2771 * fields with the specified <tt>tag</tt> are checked for equality. 2772 * 2773 * @param anObject 2774 * Another message. 2775 * @param tag 2776 * Tag to look for. 2777 * @param ignoreCase 2778 * If <tt>true</tt> then tag search is case-insensitive. 2779 * @return <tt>true</tt> if another message is equal to this message. 2780 * Otherwise, returns <tt>false</tt>. 2781 * @see #equals(Object) 2782 */ 2783 public boolean equalsUsingTaggedFields(Object anObject, String tag, 2784 boolean ignoreCase) 2785 { 2786 // Sanity checks 2787 if (this == anObject) 2788 return true; 2789 else if (!(anObject instanceof RMsg)) 2790 return false; 2791 2792 RMsg anotherMsg = (RMsg) anObject; 2793 2794 // Compare number of tagged fields - quick check to compare messages 2795 if (getTaggedFields(tag, ignoreCase).size() != anotherMsg 2796 .getTaggedFields(tag, ignoreCase).size()) 2797 return false; 2798 2799 // Compare tagged fields 2800 for (java.util.Iterator iter = getTaggedFields(tag, ignoreCase) 2801 .iterator(); iter.hasNext();) 2802 { 2803 try 2804 { 2805 String fldName = (String) iter.next(); 2806 RFld fld = getField(fldName); 2807 if (!anotherMsg.fieldExists(fldName)) 2808 return false; 2809 2810 boolean fldValSet = fld.isValSet(); 2811 2812 RFld anotherFld = anotherMsg.getField(fldName); 2813 boolean anotherFldValSet = anotherFld.isValSet(); 2814 2815 // Skip this field if it is set in neither message 2816 if (!fldValSet && !anotherFldValSet) 2817 continue; 2818 // If this field is not set in ONE of the messages, or if the 2819 // field values 2820 // are not equal in the two messages, then the messages are not 2821 // equal 2822 else if ((fldValSet != anotherFldValSet) 2823 || (!fld.equals(anotherFld))) 2824 return false; 2825 } 2826 catch (FieldValidationException ex) 2827 { 2828 return false; 2829 } 2830 } 2831 return true; 2832 } 2833 2834 /*** 2835 * Check if another message is equal to this message. Equality is defined as 2836 * both messages having the same number of fields, and all fields having the 2837 * same, non-null, value. It returns(in sb) a formatted string of fields 2838 * that fail the test 2839 * 2840 * @param anObject 2841 * Another message. 2842 * @param sbResultText - 2843 * StringBuffer object to print non-matching fields 2844 * @return <tt>true</tt> if another message is equal to this message. 2845 * Otherwise, returns <tt>false</tt>. 2846 */ 2847 public boolean equalsDebug(Object anObject, StringBuffer sbResultText) 2848 { 2849 boolean l_stat = true; 2850 StringBuffer sb = new StringBuffer(); 2851 2852 // Sanity checks 2853 if (this == anObject) 2854 return true; 2855 else if (anObject == null || !(anObject instanceof RMsg)) 2856 return false; 2857 2858 // Compare number of fields 2859 RMsg anotherMsg = (RMsg) anObject; 2860 if (getFieldCount() != anotherMsg.getFieldCount()) 2861 return false; 2862 2863 // Compare each field 2864 RFld[] fldsArray = getFieldsAsArray(); 2865 for (int i = fldsArray.length - 1; i >= 0; --i) 2866 { 2867 RFld fld = fldsArray[i]; 2868 String fldName = fld.getName(); 2869 try 2870 { 2871 RFld anotherFld = anotherMsg.getField(fldName); 2872 if (!fld.isValSet() && !anotherFld.isValSet()) 2873 continue; 2874 else if (!(fld.equals(anotherFld))) 2875 { 2876 sb.append(" Field -> " + fldName + " this = [" 2877 + fld.getValueAsString() + "] another = [" 2878 + anotherFld.getValueAsString() + "] \n"); 2879 l_stat = false; 2880 2881 } 2882 } 2883 catch (FieldValidationException ex) 2884 { 2885 sb.append(" Field -> " + fldName + " contains null \n"); 2886 l_stat = false; 2887 } 2888 } 2889 if (!l_stat) 2890 { 2891 sbResultText.setLength(0); 2892 try 2893 { 2894 sbResultText.append("\n********" + getString("MessageName") 2895 + "**************************\n"); 2896 } 2897 catch (Exception e) 2898 { 2899 sbResultText.append("\n********" + this 2900 + "*******************************\n"); 2901 } 2902 sbResultText.append(sb.toString()); 2903 sbResultText 2904 .append("**************************************************************\n"); 2905 return false; 2906 } 2907 return true; 2908 } 2909 2910 /*** 2911 * Check if another message is equal to this message based on a subset of 2912 * the fields in the messages. This is the debug version that prints the 2913 * fields that do not match 2914 * 2915 * @param anObject 2916 * Another message. 2917 * @param ignoreFields 2918 * Field to ignore when checking for equality. 2919 */ 2920 public boolean equalIgnoreValuesDebug(Object anObject, 2921 java.util.Vector ignoreFields) 2922 { 2923 // Sanity checks 2924 if (this == anObject) 2925 return true; 2926 else if (anObject == null || !(anObject instanceof RMsg)) 2927 return false; 2928 2929 // Compare number of fields 2930 RMsg anotherMsg = (RMsg) anObject; 2931 if (getFieldCount() != anotherMsg.getFieldCount()) 2932 return false; 2933 2934 boolean isEqual = true; 2935 StringBuffer sb = new StringBuffer(); 2936 // Compare each field, ignoring the values of those in ignoreFields. 2937 RFld[] fldsArray = getFieldsAsArray(); 2938 for (int i = fldsArray.length - 1; i >= 0; --i) 2939 { 2940 try 2941 { 2942 RFld fld = fldsArray[i]; 2943 String fldName = fld.getName(); 2944 2945 //if current iteration of field is not in the ignoreFields, 2946 //compare values. 2947 if (!ignoreFields.contains(fldName)) 2948 { 2949 RFld anotherFld = anotherMsg.getField(fldName); 2950 if (!fld.isValSet() && !anotherFld.isValSet()) 2951 continue; 2952 2953 if (!(fld.equals(anotherFld))) 2954 { 2955 sb.append(" FieldName -> " + fldName + " this = [" 2956 + fld.getValueAsString() + "] another = [" 2957 + anotherFld.getValueAsString() + "] \n"); 2958 isEqual = false; 2959 } 2960 } 2961 } 2962 catch (FieldValidationException ex) 2963 { 2964 return false; 2965 } 2966 } //end while 2967 if (sb.length() != 0) 2968 { 2969 try 2970 { 2971 System.out.println("********" + getString("MessageName") 2972 + "*********"); 2973 } 2974 catch (FieldValidationException e) 2975 { 2976 System.out 2977 .println("\n******** Could not obtain field MessageName ****"); 2978 } 2979 System.out.println(sb.toString()); 2980 System.out.println("\n**************************"); 2981 } 2982 2983 return isEqual; 2984 } 2985 2986 /*** 2987 * Check if another message is equal to this message based on a subset of 2988 * the fields in the messages. 2989 * 2990 * @param anObject 2991 * Another message. 2992 * @param ignoreFields 2993 * Fields to ignore when checking for equality. 2994 */ 2995 public boolean equalIgnoreValues(Object anObject, 2996 java.util.Vector ignoreFields) 2997 { 2998 // Sanity checks 2999 if (this == anObject) 3000 return true; 3001 else if (anObject == null || !(anObject instanceof RMsg)) 3002 return false; 3003 3004 // Compare number of fields 3005 RMsg anotherMsg = (RMsg) anObject; 3006 if (getFieldCount() != anotherMsg.getFieldCount()) 3007 return false; 3008 3009 // Compare each field, ignoring the values of those in ignoreFields. 3010 RFld[] fldsArray = getFieldsAsArray(); 3011 for (int i = fldsArray.length - 1; i >= 0; --i) 3012 { 3013 try 3014 { 3015 RFld fld = fldsArray[i]; 3016 String fldName = fld.getName(); 3017 3018 // if current iteration of field is not in the ignoreFields, 3019 // compare values. 3020 if (!ignoreFields.contains(fldName)) 3021 { 3022 RFld anotherFld = anotherMsg.getField(fldName); 3023 if (!fld.isValSet() && !anotherFld.isValSet()) 3024 continue; 3025 3026 //System.out.println("Comparing field " + fldName); 3027 if (!(fld.equals(anotherFld))) 3028 return false; 3029 } 3030 } 3031 catch (FieldValidationException ex) 3032 { 3033 return false; 3034 } 3035 } 3036 return true; 3037 } 3038 3039 /*** 3040 * Similar to the comments for hashcode in <tt>java.util.Hashtable</tt> 3041 * Returns the hash code value for the Message. The hash code of the message 3042 * is defined to be the sum of the hash code of each field value in the 3043 * message. It is important that all the message field classes also 3044 * implement equals and hashCode in a similar manner. The broad design of 3045 * this method is taken from the book 3046 * <tt>Effective Java (first edition) by Joshua Bloch</tt> 3047 * 3048 * @return Hash code value for this message. 3049 */ 3050 public int hashCode() 3051 { 3052 int result = 17; 3053 RFld[] fldsArray = getFieldsAsArray(); 3054 for (int i = fldsArray.length - 1; i >= 0; --i) 3055 { 3056 RFld fld = fldsArray[i]; 3057 int hashCode = 0; 3058 if (fld.isValSet()) 3059 hashCode = fld.hashCode(); 3060 result = (37 * result) + hashCode; 3061 } 3062 return result; 3063 } 3064 3065 /*** 3066 * Version field. 3067 */ 3068 protected String version_; 3069 3070 /*** 3071 * Message name. 3072 */ 3073 protected String name_; 3074 3075 /*** 3076 * Message description. 3077 */ 3078 protected String desc_; 3079 3080 /*** 3081 * Flag to make message immutable. 3082 */ 3083 protected boolean locked_; 3084 3085 /*** 3086 * Fixed send subject. If the send subject is fixed by the application then 3087 * the subject specification is ignored in comnputing the send subject. 3088 */ 3089 protected String fixedSendSubject_; 3090 3091 /*** 3092 * The send/listen subject specification for this message. The subject 3093 * specification can either be static - e.g. UM.ADMIN, or parameterized - 3094 * e.g. UM.[ClientId].ADMIN. If the subject is parameterized then the 3095 * parameters must be the names of String fields in the message. Multiple 3096 * send/listen subjects may be specified by provided a comma separated list 3097 * of send subjects - e.g. UM.ADMIN,UM.[ClientId].ADMIN. 3098 */ 3099 protected String[] subjectSpec_; 3100 3101 /*** 3102 * For each entry in subjectSpec_ this array contains the names of the 3103 * parameterized components. For example, if subjectSpec_[0] is 3104 * FB.FE.[ClientId].[UserId].ORD then subjectSpecComponents_[0] will contain 3105 * twl elements - ClientId and UserId. 3106 */ 3107 protected String[][] subjectSpecComponents_; 3108 3109 /*** 3110 * Message fields. 3111 */ 3112 protected java.util.Map flds_; 3113 3114 protected transient RFld[] fldsArray_; 3115 3116 /*** 3117 * Message fields - key into the <tt>Map</tt> is uppercase field names. 3118 */ 3119 protected java.util.Map noCaseFlds_; 3120 3121 /*** 3122 * Field to indicate if this message has no fields. 3123 */ 3124 protected boolean emptyMsg_; 3125 3126 /*** 3127 * Required field groups. 3128 * 3129 * @see RRequiredGrp 3130 */ 3131 protected java.util.List reqGrps_; 3132 3133 /*** 3134 * Subject specification parameters. 3135 */ 3136 protected static transient java.util.Hashtable subjectParams_; 3137 3138 /*** 3139 * Delimiter for indirect subject components. 3140 */ 3141 protected static final transient char INDIRECT_COMPONENT_DELIMITER = ':'; 3142 3143 /*** 3144 * Delimiter for multiple subject specifications. 3145 */ 3146 protected static final transient String NESTED_FIELDNAME_DELIMITER = "."; 3147 3148 /*** 3149 * Delimiter for multiple subject specifications. 3150 */ 3151 protected static final transient String SUBJECT_DELIMITER = ","; 3152 3153 /*** 3154 * Delimiter for start of parameterized subject name component. 3155 */ 3156 protected static final transient char SUBJECT_PARAM_START = '['; 3157 3158 /*** 3159 * Delimiter for end of parameterized subject name component. 3160 */ 3161 protected static final transient char SUBJECT_PARAM_END = ']'; 3162 3163 /*** 3164 * Wildcard for parameterized subject name component - we use a 3165 */ 3166 protected static final transient String SUBJECT_WILDCARD = "*"; 3167 3168 /*** 3169 * Delimiter for exposed fields within string representation. 3170 */ 3171 protected static final transient char EXPOSED_FIELD_DELIMITER = '&'; 3172 3173 /*** 3174 * Delimiter for fields within hashtable entry string representation. 3175 */ 3176 protected static final transient char HASHTABLE_ENTRY_DELIMITER = ','; 3177 3178 /*** 3179 * Start delimiter for nested fields within string representation. 3180 */ 3181 protected static final transient char NESTED_FIELD_START = '{'; 3182 3183 /*** 3184 * End delimiter for nested fields within string representation. 3185 */ 3186 protected static final transient char NESTED_FIELD_END = '}'; 3187 3188 /*** 3189 * End delimiter for nested fields within string representation. 3190 */ 3191 protected static final transient char FIELD_EQUAL = '='; 3192 3193 /*** 3194 * Not Applicable (not set) value. 3195 */ 3196 protected static final transient String NA_VALUE = "N/A"; 3197 3198 /*** 3199 * XML tag for this element type. 3200 */ 3201 static transient String XML_TAG = "msg"; 3202 3203 /*** 3204 * Attribute 'name' of JDOM element. 3205 */ 3206 protected static transient String XML_ATTR_NAME = "name"; 3207 3208 /*** 3209 * Flag to indicate whether access to fields is done in a case-insensitive 3210 * manner. Default is <tt>true</tt>. 3211 */ 3212 protected static transient boolean noCaseFldNames_ = true; 3213 3214 private static transient final String[] NOSUBJECT_ARRAY = new String[0]; 3215 }

This page was automatically generated by Maven