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