001    package org.vmdb.hl7;
002    
003    import java.util.*;
004    
005    /**
006     * <p><Title:> Base Class for All Types of HL7 Segments. </p>
007     * <p>Description: HL7 Network Connectivity For VMDB. </p>
008     * <p>Copyright: Copyright (c) 2002-2003. </p>
009     * <p>Company: Veterinary Medical Database (VMDB). </p>
010     * <p>A segment is a collection of related fields whose positions are specified
011     * in the segment rule.  The primary function of the base class is to handle the
012     * complex processes of parsing and building segments from and to HL7 and XML.
013     * Each derived class provides a rule.  The base class passes that rule to a
014     * RuleParser object which acts as a director with calls back to this object to
015     * read the input string, add fields, etc..  </p>
016     * <p>The base segment class also provides the mechanics for accessing fields by
017     * position based upon an index.  Most of the class is made up of a huge variety
018     * of methods for getting, setting, and listing fields.  These are normally intended
019     * to be used by derived classes to implement named accessor methods.
020     * In most cases, an application should use these higher-level set, get,
021     * and list methods that provide more segment and message specific access.  The
022     * base getField() and setField() methods are made public to provide the ability to
023     * extend messages to any of the infinite possible variations allowed under HL7.</p>
024     * @author Michael K. Martin
025     * @version 1.0
026     */
027    
028    public class HL7Segment extends HL7Object{
029       protected Vector vFields;
030       protected int iMaxFields;
031       protected HL7SegmentContainer msgParent;
032       protected String sNextField;
033       protected StringList slFields;
034       private String sNm = "ZZZ";
035       private String sRl = "DT{*}";
036    
037       protected HL7Segment() {
038          vFields = new Vector();
039          setName( sNm );
040          setRule( sRl );
041       }
042    
043       /**
044        * Construct a segment as part of a specific message or loop.
045        * @param msgParent HL7SegmentContainer to allow this segment to make
046        * calls to its parent message or loop.
047        */
048       public HL7Segment( HL7SegmentContainer msgParent ) {
049          vFields = new Vector();
050          this.msgParent = msgParent;
051          setName( sNm );
052          setRule( sRl );
053       }
054    
055       protected void setParent( HL7SegmentContainer msgParent ) {
056          this.msgParent = msgParent;
057       }
058    
059       protected boolean addField( HL7Element fField ) {
060          if( fField != null ) {
061             vFields.add( fField );
062             return true;
063          }
064          else
065             return false;
066       }
067    
068       /**
069        * Get an Iterator over the HL7Element derived objects that make up
070        * this segment.
071        * @return Iterator over all the Elements in this segment.
072        */
073       public Iterator iterator() {
074          if( vFields == null ) return null;
075          else return vFields.iterator();
076       }
077    
078       /**
079        * Factory method to read an HL7 segment as a delimited string and
080        * produce a segment object of appropriate subclass.
081        * @param sSegment String with whole row
082        * @param msgParent parent Message
083        * @return HL7Segment or subclass or null if not parsable.
084        */
085       static HL7Segment fromString( String sSegment, HL7SegmentContainer msgParent ) {
086          if( sSegment == null ) {
087             return null;
088          }
089            // Read separators from MSH segment
090          if( sSegment.substring(0,3).equalsIgnoreCase( "MSH" ) ) {
091             MSHSegment mshSeg = new MSHSegment( msgParent );
092             String sSeparators = sSegment.substring(3,8);
093             if( msgParent != null )
094                msgParent.setSeparators( sSeparators );
095             mshSeg.setSeparators( sSeparators );
096             mshSeg.readString( sSegment );
097             return mshSeg;
098             // Read other separators.
099          }
100          else {
101             if( msgParent == null || msgParent.getSeparators() == null ) return null;
102             HL7Segment sSeg;
103             try {
104                Class c = Class.forName( "org.vmdb.hl7." + sSegment.substring(0,3) + "Segment" );
105                sSeg = (HL7Segment)c.newInstance();
106                sSeg.setParent( msgParent );
107             }
108             catch( Exception e ) {
109                // Generic HL7Segment not working quite right yet.
110                sSeg = new HL7Segment( msgParent );
111                sSeg.setName( sSegment.substring(0,3) );
112             }
113             // Actually do specific classes once available.
114             sSeg.setSeparators( msgParent.getSeparators() );
115             sSeg.readString( sSegment );
116             return sSeg;
117          }
118       }
119    
120       boolean readString( String sSegment ) {
121          // need to read tokens themselves so we can account for empty fields
122          char cEsc = getSeparator( ESC_SEP );
123          // hack to avoid being confused by the escape character in MSH:3
124          if( getName().equalsIgnoreCase( "MSH" ) ) cEsc = StringList.NONE;
125          slFields = new StringList( sSegment, getSeparator( FIELD_SEP ) );
126          if( slFields.hasMoreStrings() ) {
127             sNextField = slFields.nextString();
128             initialize();
129             // Pass this pointer so parser knows to call my processSegment method.
130             RuleParser p = new RuleParser();
131             try {
132                if( p.parseFields( getRule(), this ) > 0 )
133                   return true;
134             }
135             catch( Exception e ) {
136                System.err.println( e.toString() );
137                e.printStackTrace();
138             }
139          }
140          return false;
141       }
142    
143       void initialize() {
144          // need to read tokens themselves so we can account for empty fields
145          char cEsc = getSeparator( ESC_SEP );
146          // hack to avoid being confused by the escape character in MSH:3
147          if( getName().equalsIgnoreCase( "MSH" ) ) cEsc = StringList.NONE;
148          RuleParser p = new RuleParser();
149          try {
150             iMaxFields = p.initializeFields( getRule(), this );
151          }
152          catch( Exception e ) {
153             System.err.println( e.toString() );
154             e.printStackTrace();
155          }
156          ((HL7Element)getField( 0 )).setValue( getName() );
157       }
158    
159       protected void addEmptyFields( int iFieldNo ) {
160          // need to read tokens themselves so we can account for empty fields
161          char cEsc = getSeparator( ESC_SEP );
162          // hack to avoid being confused by the escape character in MSH:3
163          if( getName().equalsIgnoreCase( "MSH" ) ) cEsc = StringList.NONE;
164          RuleParser p = new RuleParser();
165          try {
166             p.addFields( getRule(), this, vFields.size(), iFieldNo );
167          }
168          catch( Exception e ) {
169             System.err.println( e.toString() );
170             e.printStackTrace();
171          }
172          //((SimpleElement)getField( 0 )).setValue( getName() );
173       }
174    
175       /**
176        * Output this segment as an HL7 String.
177        * @return String with segment and all contained fields as delimited HL7.
178        */
179       public String toString() {
180          Iterator i = vFields.iterator();
181          StringBuffer sb = new StringBuffer();
182          while( i.hasNext() ) {
183             HL7Element eNext = (HL7Element)i.next();
184             sb.append( eNext.toString() );
185             sb.append( getSeparator( FIELD_SEP ) );
186          }
187          sb.append( "\n" );
188          return sb.toString();
189       }
190    
191       /**
192        * Output the this segment as XML.<br><br>
193        * Output is the DOM element for that segment and all its contained objects.
194        * @param iDepth int value for the number of spaces to indent this object.  Used just
195        * to make the XML easier to read as unformatted text.
196        * @return foratted XML text.
197        */
198       public String toXML( int iDepth ) {
199          Iterator i = vFields.iterator();
200          StringBuffer sb = new StringBuffer();
201          int iField = 0;
202          for( int x = 0; x < iDepth; x++ ) sb.append( " " );
203          sb.append( '<' );
204          sb.append( sName );
205          sb.append( ">\n" );
206          while( i.hasNext() ) {
207             HL7Element eNext = (HL7Element)i.next();
208             if( iField++ > 0 )  // Be sure to skip zero element with name.
209                sb.append( eNext.toXML( iDepth + 1 ) );
210          }
211          for( int x = 0; x < iDepth; x++ ) sb.append( " " );
212          sb.append( "</" );
213          sb.append( sName );
214          sb.append( ">\n" );
215          return sb.toString();
216       }
217    
218       boolean segmentComplete() {
219          return( !slFields.hasMoreStrings() );
220       }
221    
222       /**
223        * Add a new field in the specified name and type, at the specified location.<br>
224        * This is <i>only</i> to be called by the rule parser object acting as director
225        * to add a field of the correct type and name based on the rule string.  Lacking
226        * a "friend" access permission setting, this is restricted to package access.
227        *
228        * @param sFieldName String with field name based on segment and position.  Example:
229        * "PID.3"
230        * @param sFieldType String with HL7 data type.  Example: "CX"
231        * @param bRepeatable Boolean true if this is a repeatable field.  If so, the added
232        * field will be either be added to inside a RepeatElement object.
233        */
234       void addField( String sFieldName, String sFieldType, boolean bRepeatable ) {
235          HL7Element e = null;
236          if( bRepeatable ) {
237             e = new RepeatElement();
238             e.setName( sFieldName );
239             e.setType( sFieldType );
240          }
241          else {
242             e = HL7Element.makeElement( HL7Element.FIELD, getSeparators(), sFieldType, sFieldName );
243          }
244          vFields.add( e );
245       }
246    
247    
248       /**
249        * Add a new field in the specified name and type, at the specified location
250        * with the data read from the input data stream.<br>
251        * This is <i>only</i> to be called by the rule parser object acting as director
252        * to add a field of the correct type and name based on the rule string.  Lacking
253        * a "friend" access permission setting, this is restricted to package access.
254        *
255        * @param sFieldName String with field name based on segment and position.  Example:
256        * "PID.3"
257        * @param sFieldType String with HL7 data type.  Example: "CX"
258        * @param bRepeatable Boolean true if this is a repeatable field.  If so, the added
259        * field will be either be added to inside a RepeatElement object.
260        * @return boolean true if data fitting the field type were found and added, or
261        * false if the next field could not be parsed as the data type specified in sType
262        */
263       boolean processField( String sField, String sType, boolean bRepeatable )
264              throws MalformedFieldException,
265                     MalformedSegmentException {
266          boolean bRetVal = false;
267          if( sType == null || sType.length() == 0 || sNextField == null )
268             bRetVal = false;
269          else {
270             if( sField != null && sField.equals( "OBX.5" ) && getField(2) != null ) {
271                sType = getField( 2 ).getValue();
272             }
273             StringList sl = new StringList( sNextField, getSeparator( REP_SEP ) );
274             if( !bRepeatable && sl.size() > 1 ) {
275                throw new MalformedFieldException( "Repeat character in non-repeatable field:\n" + sNextField );
276             }
277             HL7Element e = null;
278             while( sl.hasMoreStrings() ) {
279                String sValue = sl.nextString();
280                e = HL7Element.makeElement( HL7Element.FIELD, getSeparators(), sType, sField );
281                e.readString( sValue );
282                setField( e, sField, bRepeatable );
283             }
284             bRetVal = true;
285             if( slFields.hasMoreStrings() )
286                sNextField = slFields.nextString();
287             else
288                sNextField = null;
289          }
290          return bRetVal;
291       }// End processFields
292    
293       /**
294        * Set the field at position specified to the HL7Element derived object
295        * provided.<br><br>
296        * The following allow set and get by position and will be used by named
297        * segment subclasses for their setters and accessors.
298        * Based on HL7 field number i.e., 1 based index.
299        * @param eField The specific object to be inserted by reference.
300        * @param sFieldName String with field name based on segment and position.  Example:
301        * "PID.3"
302        * @param bRepeatable Boolean true if this is a repeatable field.
303        * @throws NumberFormatException if the string in sFieldName cannot be
304        * parsed to a string segment name plus a period and an integer.
305        * @throws ArrayIndexOutOfBoundsException if the field specified in sFieldName is
306        * either zero or less or greater than the number of fields.
307        * @throws MalformedSegmentException if the HL7Element provided as eField does not
308        * have the type required by rule for this field or when attempting to add to
309        * a non-repeatable field.
310        */
311       public void setField( HL7Element eField, String sFieldName, boolean bRepeatable )
312             throws NumberFormatException,
313                    ArrayIndexOutOfBoundsException,
314                    MalformedSegmentException
315       {
316          int iFieldNo = -1;
317          try {
318             String sName = sFieldName.substring(0,sFieldName.indexOf("."));
319             String sNum = sFieldName.substring(sFieldName.indexOf(".")+1);
320             iFieldNo = Integer.parseInt( sNum );
321          }
322          catch( NumberFormatException e ) {
323             throw new NumberFormatException( "Cannot parse " + sFieldName
324                                            + " as Seg.integer for field number.\n"
325                                              + e.getMessage() );
326          }
327          setField( eField, iFieldNo );
328       }
329    
330       /**
331        * Set the field at position specified to the HL7Element derived object
332        * provided.<br><br>
333        * The following allow set and get by position and will be used by named
334        * segment subclasses for their setters and accessors.
335        * Based on HL7 field number i.e., 1 based index.
336        * @param eField The specific object to be inserted by reference.
337        * @param sFieldName String with field name based on segment and position.  Example:
338        * "PID.3"
339        * @throws NumberFormatException if the string in sFieldName cannot be
340        * parsed to a string segment name plus a period and an integer.
341        * @throws ArrayIndexOutOfBoundsException if the field specified in sFieldName is
342        * either zero or less or greater than the number of fields.
343        * @throws MalformedSegmentException if the HL7Element provided as eField does not
344        * have the type required by rule for this field.
345        */
346       public void setField( HL7Element eField, String sFieldName )
347             throws NumberFormatException,
348                    ArrayIndexOutOfBoundsException,
349                    MalformedSegmentException
350       {
351          setField( eField, sFieldName, false );
352       }
353    
354       /**
355        * Set the field at position specified to a SimpleElement with the value
356        * provided.<br><br>
357        * The following allow set and get by position and will be used by named
358        * segment subclasses for their setters and accessors.
359        * Based on HL7 field number i.e., 1 based index.
360        * @param sField String value for any of the simple types.
361        * @param sFieldName String with field name based on segment and position.  Example:
362        * "PID.3"
363        * @param bRepeatable Boolean true if this is a repeatable field.
364        * @throws NumberFormatException if the string in sFieldName cannot be
365        * parsed to a string segment name plus a period and an integer.
366        * @throws ArrayIndexOutOfBoundsException if the field specified in sFieldName is
367        * either zero or less or greater than the number of fields.
368        * @throws MalformedSegmentException if the HL7Element provided as eField does not
369        * have the type required by rule for this field.
370        */
371       public void setField( String sField, String sFieldName )
372             throws NumberFormatException,
373                    ArrayIndexOutOfBoundsException,
374                    MalformedSegmentException
375       {
376          int iFieldNo = -1;
377          try {
378             String sName = sFieldName.substring(0,sFieldName.indexOf("."));
379             String sNum = sFieldName.substring(sFieldName.indexOf(".")+1);
380             iFieldNo = Integer.parseInt( sNum );
381          }
382          catch( NumberFormatException e ) {
383             throw new NumberFormatException( "Cannot parse " + sFieldName
384                                            + " as Seg.integer for field number.\n"
385                                              + e.getMessage() );
386          }
387          setField( sField, iFieldNo );
388       }
389    
390       /**
391        * Set the field at position specified to the HL7Element derived object
392        * provided.<br><br>
393        * The following allow set and get by position and will be used by named
394        * segment subclasses for their setters and accessors.
395        * Based on HL7 field number i.e., 1 based index.
396        * @param eField The specific object to be inserted by reference.
397        * @param iFieldNo Integer field number.
398        * @param bRepeatable Boolean true if this is a repeatable field.
399        * @throws ArrayIndexOutOfBoundsException if iFieldNo points to a field
400        * less than zero or greater than the number of fields allowed in the message
401        * rule
402        * @throws MalformedSegmentException if the HL7Element provided as eField does not
403        * have the type required by rule for this field or when attempting to add to
404        * a non-repeatable field.
405        */
406       public void setField( HL7Element eField, int iFieldNo, boolean bAdd )
407          throws ArrayIndexOutOfBoundsException,
408                 MalformedSegmentException
409       {
410          eField.setName( getName() + "." + iFieldNo );
411          if( iFieldNo < 0 || iFieldNo >= iMaxFields )
412             throw new ArrayIndexOutOfBoundsException();
413          else if( vFields.size() > iFieldNo ){
414             Object o = vFields.elementAt( iFieldNo );
415             if( o instanceof RepeatElement ) {
416                RepeatElement re = (RepeatElement)o;
417                if( !bAdd )
418                   re.clear();
419                re.addElement( eField );
420             }
421             else {
422                if( bAdd )
423                   throw new MalformedSegmentException( "Attempt to add to non-repeatable field" );
424                String sType = getField( iFieldNo ).getType();
425                if( !sType.equals("*") && !sType.equalsIgnoreCase( eField.getType() ) ) {
426                   throw new MalformedSegmentException( "Found field type " + eField.getType() +
427                                                        " but expected " + sType  );
428                }
429                vFields.setElementAt( eField, iFieldNo );
430             }
431          }
432          else if( iFieldNo <= iMaxFields ) {
433             addEmptyFields( iFieldNo );
434             String sType = getField( iFieldNo ).getType();
435             if( !sType.equals("*") && !sType.equalsIgnoreCase( eField.getType() ) ) {
436                throw new MalformedSegmentException( "Found field type " + eField.getType() +
437                                                     " but expected " + sType  );
438             }
439             Object o = vFields.elementAt( iFieldNo );
440             if( o instanceof RepeatElement ) {
441                RepeatElement re = (RepeatElement)o;
442                re.addElement( eField );
443             }
444             else {
445                vFields.setElementAt( eField, iFieldNo );
446             }
447          }
448       }
449    
450       /**
451        * Set the field at position specified to the HL7Element derived object
452        * provided.<br><br>
453        * The following allow set and get by position and will be used by named
454        * segment subclasses for their setters and accessors.
455        * Based on HL7 field number i.e., 1 based index.
456        * @param eField The specific object to be inserted by reference.
457        * @param iFieldNo Integer field number.
458        * @throws ArrayIndexOutOfBoundsException if iFieldNo points to a field
459        * less than zero or greater than the number of fields allowed in the message
460        * rule
461        * @throws MalformedSegmentException if the HL7Element provided as eField does not
462        * have the type required by rule for this field.
463        */
464       public void setField( HL7Element eField, int iFieldNo )
465          throws ArrayIndexOutOfBoundsException,
466                 MalformedSegmentException
467       {
468          setField( eField, iFieldNo, false );
469       }
470    
471       /**
472        * Set the field at position specified to a SimpleElement with the value
473        * provided.<br><br>
474        * The following allow set and get by position and will be used by named
475        * segment subclasses for their setters and accessors.
476        * Based on HL7 field number i.e., 1 based index.
477        * @param sField String value for any of the simple types.
478        * @param iFieldNo Integer field number.
479        * @param bAdd Boolean true to add rather than replace an existing value in
480        * a repeatable field.
481        * @throws ArrayIndexOutOfBoundsException if iFieldNo points to a field
482        * less than zero or greater than the number of fields allowed in the message
483        * rule
484        * @throws MalformedSegmentException if attempting to add to a non-repeatable field.
485        */
486       public void setField( String sValue, int iFieldNo, boolean bAdd )
487          throws ArrayIndexOutOfBoundsException,
488                 MalformedSegmentException
489       {
490          if( iFieldNo < 0 || iFieldNo >= iMaxFields )
491             throw new ArrayIndexOutOfBoundsException();
492          else if( vFields.size() > iFieldNo ){
493          }
494          else if( iFieldNo <= iMaxFields ) {
495             addEmptyFields( iFieldNo );
496          }
497          Object o = vFields.elementAt( iFieldNo );
498          if( o instanceof RepeatElement ) {
499             RepeatElement re = (RepeatElement)o;
500             if( !bAdd )
501                re.clear();
502             String sType = getField( iFieldNo ).getType();
503             String sName = getField( iFieldNo ).getName();
504             HL7Element e = HL7Element.makeElement( HL7Element.FIELD, getSeparators(), sType, sName );
505             e.setValue( sValue );
506             re.addElement( e );
507          }
508          else {
509             if( bAdd )
510                throw new MalformedSegmentException( "Attempt to add to non-repeatable field" );
511             HL7Element eField = (HL7Element)o;
512             eField.setValue( sValue );
513          }
514       }
515    
516    
517       /**
518        * Set the field at position specified to a SimpleElement with the value
519        * provided.<br><br>
520        * The following allow set and get by position and will be used by named
521        * segment subclasses for their setters and accessors.
522        * Based on HL7 field number i.e., 1 based index.
523        * @param sField String value for any of the simple types.
524        * @param iFieldNo Integer field number.
525        * @throws ArrayIndexOutOfBoundsException if iFieldNo points to a field
526        * less than zero or greater than the number of fields allowed in the message
527        * rule
528        */
529       public void setField( String sValue, int iFieldNo )
530          throws ArrayIndexOutOfBoundsException
531       {
532          try {
533          setField( sValue, iFieldNo, false );
534          } catch( MalformedSegmentException mse ) {
535             System.err.println( "Impossible malformed segment exception!" );
536             mse.printStackTrace();
537          }
538       }
539    
540       /**
541        * Clear the value in the specified field and remove any components and
542        * subcomponents.
543        * @param iFieldNo One based index (zero is the segment name) of field to clear.
544        * @throws ArrayIndexOutOfBoundsException if iFieldNo points to a field
545        * less than zero or greater than the number of fields allowed in the message
546        * rule
547        */
548       public void clearField( int iFieldNo )
549          throws ArrayIndexOutOfBoundsException
550       {
551          if( iFieldNo < 0 || iFieldNo >= iMaxFields )
552             throw new ArrayIndexOutOfBoundsException();
553          else if( vFields.size() > iFieldNo ){
554             Object o = vFields.elementAt( iFieldNo );
555             if( o instanceof HL7Element ) {
556                HL7Element he = (HL7Element)o;
557                he.clear();
558             }
559          }
560          else if( iFieldNo < iMaxFields ) {
561             // This makes sense but since the field hasn't been set
562             // we don't need to do anything.
563          }
564       }
565    
566       /**
567        * Get Field in Segment by position as named in HL7, i.e., 1 based
568        * index (zero is the segment name).<br><br>
569        * If this is a repeating field, returns the first value.
570        * @param iFieldNo One based index (zero is the segment name) of field.
571        * @return The element at position iFieldNo as an HL7Element derived object.
572        * @throws ArrayIndexOutOfBoundsException if iFieldNo points to a field
573        * less than zero or greater than the number of fields allowed in the message
574        * rule
575        */
576       public HL7Element getField( int iFieldNo )
577          throws ArrayIndexOutOfBoundsException
578       {
579          if( iFieldNo < 0 || iFieldNo >= iMaxFields )
580             throw new ArrayIndexOutOfBoundsException();
581          else if( vFields.size() > iFieldNo ){
582             HL7Element hE = (HL7Element)vFields.elementAt( iFieldNo );
583             if( hE == null )
584                return null;
585             else {
586                if( hE instanceof RepeatElement ){
587                   return ((RepeatElement)hE).firstElement();
588                }
589                else
590                   return hE;
591             }
592          }
593          else {
594             return null;
595          }
596       }
597    
598       /**
599        * Get Iterator over all instances of a repeatable Field in Segment by
600        * position as named in HL7, i.e., 1 based index (zero is the segment name).<br><br>
601        * @param iFieldNo One based index (zero is the segment name) of field.
602        * @return Iterator over the elements at position iFieldNo as an HL7Element derived objects.
603        * @throws ArrayIndexOutOfBoundsException if iFieldNo points to a field
604        * less than zero or greater than the number of fields allowed in the message
605        * rule
606        */
607       public Iterator listFields( int iFieldNo )
608          throws ArrayIndexOutOfBoundsException
609       {
610          if( iFieldNo < 0 || iFieldNo >= iMaxFields )
611             throw new ArrayIndexOutOfBoundsException();
612          else if( vFields.size() > iFieldNo ){
613             HL7Element hE = (HL7Element)vFields.elementAt( iFieldNo );
614             if( hE == null )
615                return null;
616             else {
617                if( hE instanceof RepeatElement )
618                   return ((RepeatElement)hE).iterator();
619                 // This should just be a convenience in case called against
620                 // a non-repeatable Field.
621                else {
622                   Vector vMatch = new Vector();
623                   vMatch.add( hE );
624                   return vMatch.iterator();
625                }
626             }
627          }
628          else {
629             return null;
630          }
631       }
632    
633       /**
634        * Get Field Value in Segment by position as named in HL7, i.e., 1 based index.
635        * @param iFieldNo One based index (zero is the segment name) of field.
636        * @return String value of the field or the first componet of the field
637        * specified.
638        * @throws ArrayIndexOutOfBoundsException if iFieldNo points to a field
639        * less than zero or greater than the number of fields allowed in the message
640        * rule
641        */
642       public String getFieldValue( int iFieldNo )
643          throws ArrayIndexOutOfBoundsException
644       {
645          if( iFieldNo < 0 || iFieldNo >= iMaxFields )
646             throw new ArrayIndexOutOfBoundsException();
647          else if( vFields.size() > iFieldNo ){
648             if( vFields.elementAt( iFieldNo ) != null )
649                return ((HL7Element)vFields.elementAt( iFieldNo )).getValue();
650             else
651                return "";
652          }
653          else {
654             return "";
655          }
656       }
657    
658    } // End class HL7Segment
659