001 package org.vmdb.hl7;
002
003 import java.util.*;
004
005 /**
006 * <p><Title:> Observation Unsolicited (ORU) Message. </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>Message class(es) form the main API for the library. In most cases, there
011 * will be simple methods for inserting and extracting values from the message
012 * structure as well as for parsing incoming messages or building outgoing
013 * messages in either delimited HL7 or the draft XML representation.</p>
014 * <p>The Observation Unsolicited (ORU) message is the approved method for
015 * submitting data to the Veterinary Medical Database (VMDB). This class
016 * implements a subset of the ORU message that meets all requirements of VMDB
017 * and parses and builds standard-compliant ORU messages. Appropriate default
018 * values are provided for required fields not used by VMDB. Limitations
019 * added by VMDB are supported and taken advantage of in order to keep the API
020 * as simple as possible. For routine processing of VMDB submissions, the only
021 * methods needed should be those provided in the ORUMessage's public interface and
022 * the public methods inherited from HL7Message.</p>
023 * <p>For more complex tasks or for anything I've missed, <i>any</i>
024 * standard-compliant ORU message should parse
025 * correctly and any of its contents be accessible using lower-level classes.
026 * Similarly, using lower-level classes it is possible to build any standard-compliant
027 * ORU message which can then be rendered as either delimited or XML version HL7.</p>
028 * <p>The XML representation of HL7 2.x introduces the concepts of groups and lists
029 * that, while present in the construction rules of delimited HL7, are not explicitly
030 * named or labelled in the messages themselves. The internal representation in
031 * this class follows the XML version with explicitly constructed groups and lists
032 * which we've combined under the general term (borrowed from X12) of "loop." Going
033 * to the lower-level access methods often requires knowing the location of a segment
034 * in this loop structure. Perhaps the simplest way to learn this loop structure
035 * is to use the library to import a delimited HL7 message of the structure you are
036 * working with, and then print it out using the toXML() method. Because all the
037 * groups and lists are explicitly named in the XML, the structure hierarchy will
038 * be right there.</p>
039 * <p>The internal representation is built up using recursive construction. The
040 * message contains segments and loops. Loops can contain segments and other loops.
041 * Segments contain fields defined by elements of specific HL7 types. These elements my
042 * be simple strings of various types (all represented by SimpleElement currently) or may
043 * be built up from components which are themselves elements and so on. Because any
044 * given message can contain a potentially infinite number of segments, the data
045 * structure is only instantiated as it is needed either from reading in segments
046 * during parsing or from setting values that reside in a segment or field not yet
047 * instantiated. This is actually implemented in the getSSS() methods on the basis
048 * that a program is only getting the segment to do something with it. Similarly,
049 * segments are intially instantiated with place holders for all fields up to the
050 * last required field. This ensures that all delimiters required for standards
051 * compliance are present when the structure is output as HL7. If a value is set
052 * for an optional field after the last required field, placeholders up to and including
053 * the new field are instantiated. Because XML uses tag labels rather than position
054 * to identify fields, these empty fields are not output in the toXML() method.</p>
055 * <p>Note: We use Java Bean like convention of getXXX and setXXX but with a few
056 * deviations. First as previously mentioned, getSSS() where SSS is a segment or loop
057 * abbreviation has the side affect of constructing the segment or loop if it does not already
058 * exist. Also, the set methods frequently take multiple parameters especially when the
059 * actual value is a mildly complex element-type such as coded entry (CE). We have
060 * added common conventional name patterns. For example addSSS() for segments that
061 * repeat and addDiagnosis(), etc., to abstract
062 * the process of adding a segment (usually OBX) holding a single data entry such
063 * as a finding (addFinding) or diagnosis (addDiagnosis). listXXX() returns an Iterator
064 * object over a collection of segments of the type specified by XXX. findEEE( XXX )
065 * methods perform a depth-first search of the object hierarchy looking for XXX.</p>
066 * <p>TODO: Add string length validation to all methods taking String input and
067 * add to documentation.</p>
068 * @author Michael K. Martin
069 * @version 1.0
070 */
071
072 public class ORUMessage extends HL7Message {
073 private String sNm = "ORU_R01";
074 private String sRl = "MSH PATIENT_RESULT[DSC]";
075 private static final String MESSAGE_TYPE = "ORU";
076 private static final String MESSAGE_EVENT = "R01";
077
078 /**
079 * Construct an empty ORU Message with type and version set. This object
080 * is ready to either build via a series of set and add calls, or to read in
081 * an HL7 or XML (future) message.
082 */
083 public ORUMessage() {
084 super();
085 setName( sNm );
086 setRule( sRl );
087 // This is the first and only event for this message so we can
088 // use the default message structure.
089 setMessageName( MESSAGE_TYPE, MESSAGE_EVENT );
090 }
091
092 /**
093 * Get the The PATIENT_RESULT loop contained in this message. If
094 * it does not exist, take the necessary steps to create it.<br><br>
095 * Chaining calls to get[*]Loop() allows the retrieval of
096 * a loop at any point in the hierarchy with knowledge that if this is the
097 * first use of any loop or loops in the hierarchy, they will be created
098 * so that the returned reference is a valid part of the message being
099 * constructed. The referenced loop can then be used to access a segment
100 * via getSSS() or addSSS() depending on the type repeatablility of the segment.
101 * @return A reference to the PATIENT_RESULTLoop object located at the
102 * appropriate place in the loop.
103 */
104 public PATIENT_RESULTLoop getPATIENT_RESULT() {
105 PATIENT_RESULTLoop loop = null;
106 if( vSegments == null ) vSegments = new Vector();
107 for( Iterator i = vSegments.iterator(); i.hasNext(); ) {
108 HL7Object o = (HL7Object)i.next();
109 if( o.getName().equals( "PATIENT_RESULT" ) ) {
110 loop = (PATIENT_RESULTLoop)o;
111 break;
112 }
113 }
114 if( loop == null ) {
115 loop = new PATIENT_RESULTLoop();
116 // make this the second segment if we have an MSH already
117 // otherwise put it at the beginning before DSC
118 int iLoc = (findSegment("MSH") != null) ? 1 : 0;
119 vSegments.add(iLoc, loop);
120 }
121 return loop;
122 }
123
124 /**
125 * Get the PID segment that should be nested within this message. If
126 * it does not exist, take the necessary steps to create it in the appropriate
127 * nested loop structure.<br><br>
128 * Note: The "get" semantics here only work correctly for segments that exist singly
129 * in a message. We break with generic HL7 here in that only under VMDB are
130 * we restricted to a single patient per message. If we drop this limitation
131 * we will need to create more complex "addPID()" semantics.
132 * @return A reference to the PIDSegment object located at the appropriate place.
133 */
134 public PIDSegment getPID() {
135 PATIENTLoop loop = getPATIENT_RESULT().getPATIENT();
136 PIDSegment pid = loop.getPID();
137 return pid;
138 }
139
140 /**
141 * Get the PV1 segment that should be nested somewhere within this loop. If
142 * it does not exist, take the necessary steps to create it in the appropriate
143 * nested loop structure.<br><br>
144 * Note: The "get" semantics here only work correctly for segments that exist singly
145 * in a message. We break with generic HL7 here in that only under VMDB are
146 * we restricted to a single patient visit per message. If we drop this limitation
147 * we will need to create more complex "addPV1()" semantics.
148 * @return A reference to the PV1Segment object located at the appropriate place in the loop.
149 */
150 public PV1Segment getPV1() {
151 PATIENT_VISITLoop loop = getPATIENT_RESULT().getPATIENT().getPATIENT_VISIT();
152 PV1Segment pv1 = loop.getPV1();
153 return pv1;
154 }
155
156 /**
157 * Get the OBR segment that should be nested somewhere within this loop. If
158 * it does not exist, take the necessary steps to create it in the appropriate
159 * nested loop structure.<br><br>
160 * Note: The "get" semantics here only work correctly for segments that exist singly
161 * in a message. We break with generic HL7 here in that only under VMDB are
162 * we restricted to a single observation request per message. If we drop this limitation
163 * we will need to create more complex "addOBR()" semantics.
164 * @return a reference to the OBRSegment object located at the appropriate place in the loop.
165 */
166 public OBRSegment getOBR() {
167 ORDER_OBSERVATIONLoop loop = getPATIENT_RESULT().getORDER_OBSERVATION();
168 OBRSegment obr = loop.getOBR();
169 return obr;
170 }
171
172 /**
173 * Get the ORC segment that should be nested somewhere within this loop. If
174 * it does not exist, take the necessary steps to create it in the appropriate
175 * nested loop structure.<br><br>
176 * @return a reference to the OBRSegment object located at the appropriate place in the loop.
177 */
178 public ORCSegment getORC() {
179 ORDER_OBSERVATIONLoop loop = getPATIENT_RESULT().getORDER_OBSERVATION();
180 ORCSegment orc = loop.getORC();
181 return orc;
182 }
183
184 /**
185 * Get the ORC segment that should be nested somewhere within this loop. If
186 * it does not exist, take the necessary steps to create it in the appropriate
187 * nested loop structure.<br><br>
188 * @return a reference to the OBRSegment object located at the appropriate place in the loop.
189 */
190 public ORCSegment getORC( String sOrderControl ) {
191 ORDER_OBSERVATIONLoop loop = getPATIENT_RESULT().getORDER_OBSERVATION(sOrderControl);
192 ORCSegment orc = loop.getORC();
193 return orc;
194 }
195
196 /**
197 * Add an OBX segment that should be located in this loop. If the loop
198 * does not exist, take the necessary steps to create it.<br><br>
199 * Note: This should really be linked to a specific OBR, but because
200 * VMDB only allows one OBR per message, we are safe like this.
201 * @return OBXSegment object newly created.
202 */
203 public OBXSegment addOBX() {
204 ORDER_OBSERVATIONLoop loop = getPATIENT_RESULT().getORDER_OBSERVATION();
205 OBXSegment obx = loop.addOBX();
206 return obx;
207 }
208
209
210 // The accessors and mutators are based on VMDB usage of the ORU Message
211 // and are designed to provide easy access to message details
212
213 // OK, this is dumb, but the first four are just to get JavaDoc to include
214 // these directly in the ORUMessage documentation.
215 /**
216 * Set the message control id.
217 * @param sMessageId String with unique identifier
218 */
219 public void setMessageControlId( String sMessageControlId ) {
220 super.setMessageControlId( sMessageControlId );
221 }
222
223 /**
224 * Get the message control id.
225 * @return String with unique identifier
226 */
227 public String getMessageControlId() {
228 return super.getMessageControlId();
229 }
230
231 /**
232 * Set the Sending facility VMDB Institution Id.
233 * @param sName String with VMDB facility name
234 * @param sId String with VMDB facility id
235 */
236 public void setSendingFacility( String sName, String sId ) {
237 super.setSendingFacility( sName, sId );
238 }
239
240 /**
241 * Get the Sending facility VMDB Institution Id.
242 * @return String with VMDB facility id
243 */
244 public String getSendingFacilityId() {
245 return super.getSendingFacilityId();
246 }
247
248 /**
249 * Get the Sending facility name.
250 * @return String with VMDB facility name
251 */
252 public String getSendingFacilityName() {
253 MSHSegment msh = getMSH();
254 return msh.getSendingFacilityName();
255 }
256
257 /**
258 * Set the Medical record number.<br><br>
259 * Medical record is defined in this logic as the identifier assigned by the
260 * sending facility. To work correctly, the sending facility identifier must
261 * be set <strong>before</strong> actions involving MRN.
262 * @param sMRN String with facility's MRN
263 */
264 public void setMedicalRecordNumber( String sMRN ) {
265 MSHSegment msh = getMSH();
266 String sThisFacility = msh.getSendingFacilityName();
267 PIDSegment pid = getPID();
268 boolean bFound = false;
269 // First try to update existing MRN
270 Iterator i = pid.listPatientIds();
271 while( i != null && i.hasNext() ) {
272 CXElement cxe = (CXElement)i.next();
273 if( cxe == null ) continue;
274 // Check assigner logic
275 String sAssigner = cxe.getAssigningAuthorityName();
276 if( sAssigner != null && sAssigner.equals( sThisFacility ) ) {
277 cxe.setIdentifier( sMRN );
278 bFound = true;
279 break;
280 }
281 }
282 // Otherwise add a new identifier
283 if( !bFound ) {
284 pid.addPatientId( sMRN, sThisFacility );
285 }
286 }
287
288 /**
289 * Get the Medical record number.<br><br>
290 * Medical record is defined in this logic as the identifier assigned by the
291 * sending facility. To work correctly, the sending facility identifier must
292 * be set <strong><i>before</i></strong> actions involving MRN.
293 * @return String with facility's MRN
294 */
295 public String getMedicalRecordNumber() {
296 MSHSegment msh = getMSH();
297 String sThisFacility = msh.getSendingFacilityName();
298 PIDSegment pid = getPID();
299 // First try to update existing MRN
300 Iterator i = pid.listPatientIds();
301 while( i.hasNext() ) {
302 CXElement cxe = (CXElement)i.next();
303 // Check assigner logic
304 if( cxe.getAssigningAuthorityName().equals( sThisFacility ) ) {
305 return cxe.getIdentifier();
306 }
307 }
308 return "";
309 }
310
311 /**
312 * Set the species as a predefined CE Element.<br><br>
313 * Often uses one of the set of predefined constants.<br>
314 * Note: If populated with a constant, subsequent calls to getSpecies() will return a
315 * reference to the constant (final static object) and cannot be modified
316 * through calls to the CEElement's methods. But why would you want to?
317 * @param ceSpecies CEElement populated with the coded species
318 */
319 public void setSpecies( CEElement ceSpecies ) {
320 PIDSegment pid = getPID();
321 pid.setSpecies( ceSpecies );
322 }
323
324 /**
325 * Set the species as the individual components of a CE Element
326 * @param sSpeciesCode String with the code for species
327 * @param sSpeciesText String with the species spelled out
328 * @param sCodeSystem String, usually "SCT," with the type of code
329 */
330 public void setSpecies( String sSpeciesCode,
331 String sSpeciesText,
332 String sCodeSystem ) {
333 PIDSegment pid = getPID();
334 pid.setSpecies( sSpeciesCode, sSpeciesText, sCodeSystem );
335 }
336
337 /**
338 * Set the species as the individual components of a CE Element
339 * @param sSpeciesCode String with the code for species
340 * @param sSpeciesText String with the species spelled out
341 * @param sCodeSystem String, usually "SCT," with the type of code
342 * @param sAltSpeciesCode String with the alternate code for the SAME species
343 * @param sAltSpeciesText String with the species spelled out as in alternate system
344 * @param sAltCodeSystem String, alternate the type of code
345 */
346 public void setSpecies( String sSpeciesCode,
347 String sSpeciesText,
348 String sCodeSystem,
349 String sAltSpeciesCode,
350 String sAltSpeciesText,
351 String sAltCodeSystem ) {
352 PIDSegment pid = getPID();
353 pid.setSpecies( sSpeciesCode, sSpeciesText, sCodeSystem,
354 sAltSpeciesCode, sAltSpeciesText, sAltCodeSystem );
355 }
356
357 /**
358 * Get the species as a predefined CE Element.<br><br>
359 * Often uses one of the set of predefined constants.<br>
360 * Note: If setSpecies was called with a constant, subsequent calls to getSpecies() will return a
361 * reference to the constant (final static object) and cannot be modified
362 * through calls to the CEElement's methods. But why would you want to?
363 * @return A reference to the CEElement populated with species
364 */
365 public CEElement getSpecies() {
366 PIDSegment pid = getPID();
367 return pid.getSpecies();
368 }
369
370 /**
371 * Get the species text.
372 * @return String species spelled out
373 */
374 public String getSpeciesText() {
375 PIDSegment pid = getPID();
376 return pid.getSpeciesText();
377 }
378
379 /**
380 * Set the breed as a predefined CE Element.<br><br>
381 * Often uses one of the set of predefined constants.<br>
382 * Note: If populated with a constant, subsequent calls to getBreed() will return a
383 * reference to the constant (final static object) and cannot be modified
384 * through calls to the CEElement's methods. But why would you want to?
385 * @param ceBreed CEElement populated with breed
386 */
387 public void setBreed( CEElement ceBreed ) {
388 PIDSegment pid = getPID();
389 pid.setBreed( ceBreed );
390 }
391
392 /**
393 * Set the breed as the individual components of a CE Element.
394 * @param sBreedCode String snomed code for breed
395 * @param sBreedText String breed spelled out
396 * @param sCodeSystem String usually SCT with type of code
397 */
398 public void setBreed( String sBreedCode,
399 String sBreedText,
400 String sCodeSystem ) {
401 PIDSegment pid = getPID();
402 pid.setBreed( sBreedCode, sBreedText, sCodeSystem );
403 }
404
405 /**
406 * Set the breed as the individual components of a CE Element.
407 * @param sBreedCode String snomed code for breed
408 * @param sBreedText String breed spelled out
409 * @param sCodeSystem String usually SCT with type of code
410 * @param sAltBreedCode String Alternate code for breed
411 * @param sAltBreedText String breed spelled out as in alternate system
412 * @param sAltCodeSystem String alternate type of code
413 */
414 public void setBreed( String sBreedCode,
415 String sBreedText,
416 String sCodeSystem,
417 String sAltBreedCode,
418 String sAltBreedText,
419 String sAltCodeSystem ) {
420 PIDSegment pid = getPID();
421 pid.setBreed( sBreedCode, sBreedText, sCodeSystem ,
422 sAltBreedCode, sAltBreedText, sAltCodeSystem);
423 }
424
425 /**
426 * Get the breed as a predefined CE Element.<br><br>
427 * Often uses one of the set of predefined constants.<br>
428 * Note: If populated with a constant, subsequent calls to getBreed() will return a
429 * reference to the constant (final static object) and cannot be modified
430 * through calls to the CEElement's methods. But why would you want to?
431 * @return A reference to the CEElement populated with breed
432 */
433 public CEElement getBreed() {
434 PIDSegment pid = getPID();
435 return pid.getBreed();
436 }
437
438 /**
439 * Get the breed text.
440 * @return String breed spelled out
441 */
442 public String getBreedText() {
443 PIDSegment pid = getPID();
444 return pid.getBreedText();
445 }
446
447 /**
448 * Set the date of birth as ISO format data string YYYYMMDD
449 * @param sDOB String with date of birth
450 */
451 public void setDateOfBirth( String sBDate ) {
452 PIDSegment pid = getPID();
453 pid.setDateOfBirth( sBDate );
454 }
455
456 /**
457 * Set the date of birth as ISO format data string YYYYMMDD
458 * @param sDOB String with date of birth
459 */
460 public void setDateOfBirth( TSElement tsBDate ) {
461 PIDSegment pid = getPID();
462 pid.setDateOfBirth( tsBDate );
463 }
464
465 /**
466 * Get the date of birth.
467 * @return String with date of birth as YYYYMMDD
468 */
469 public String getDateOfBirth() {
470 PIDSegment pid = getPID();
471 return pid.getDateOfBirth();
472 }
473
474 /**
475 * Set the gender.
476 * @param sSex String with gender as M, C, T, F, S, O, U, H, or X
477 */
478 public void setSex( String sSex ) {
479 PIDSegment pid = getPID();
480 pid.setSex( sSex );
481 }
482
483 /**
484 * Get the gender.
485 * @return String with gender code
486 */
487 public String getSex() {
488 PIDSegment pid = getPID();
489 return pid.getSex();
490 }
491
492 /**
493 * Set the weight.<br><br>
494 * Stored as OBX with loinc code 8335-2 "Body Weight Estimated" or
495 * 3141-9 "Body Weight Measured"<br>
496 * TODO: Add checking that the string supplied as sWeight parses as a numeric.<br>
497 * TODO: Add checking that the string supplied as sWeightUnits is a valid unit of measure
498 * @param sWeight String with weight in numeric form<br>
499 * @param sWeightUnits String with units in ISO or ANSI abbreviation
500 * (usually kg or lb)<br>
501 * @param bMeasured true if weight was measured rather than estimated
502 * reflected internally by loinc code 3141-9 measured vs. 8335-2 est
503 * default is true
504 */
505 public void setWeight( String sWeight, String sWeightUnits, boolean bMeasured ) {
506 // Need to construct OBX with appropriate LOINC code for measured or estimated
507 // weight observation.
508 OBXSegment obx = addOBX();
509 if( bMeasured )
510 obx.setObservationIdentifier( Loinc.BODY_WEIGHT_MEASURED );
511 else
512 obx.setObservationIdentifier( Loinc.BODY_WEIGHT_ESTIMATED );
513 try {
514 obx.setObservationValueType( "NM" );
515 obx.setObservationValue( sWeight );
516 obx.setUnits( sWeightUnits );
517 }
518 catch( MalformedFieldException mfe ) {
519 mfe.printStackTrace();
520 }
521 }
522
523 /**
524 * Set the animal's weight and weight units.<br><br>
525 * Stored as OBX with loinc code 3141-9 "Body Weight Measured." This is
526 * just a convenience method for the common case where weights are normally
527 * always measured.
528 * @param sWeight String with weight in numeric form
529 * @param sWeightUnits String with units in ISO or ANSI abbreviation
530 * (usually kg or lb)
531 */
532 public void setWeight( String sWeight, String sWeightUnits ) {
533 setWeight( sWeight, sWeightUnits, true );
534 }
535
536 /**
537 * Set the animal's weight range and weight units.<br><br>
538 * Stored as OBX with loinc code 3141-9 "Body Weight Measured." This is
539 * just a convenience method for the common case where weights are normally
540 * always measured.
541 * @param snWeightRange SNElement with coded weight range
542 * @param sWeightUnits std::string with units in ISO or ANSI abbreviation
543 * (usually kg or lb)
544 */
545 public void setWeightRange( SNElement snWeightRange, CEElement ceWeightUnits ) {
546 // Need to construct OBX with appropriate LOINC code for measured or estimated
547 // weight observation.
548 OBXSegment obx = addOBX();
549 obx.setObservationIdentifier( Loinc.BODY_WEIGHT_ESTIMATED.Clone() );
550 try {
551 obx.setObservationValueType( "SN" );
552 obx.setObservationValue( snWeightRange );
553 obx.setUnits( ceWeightUnits );
554 }
555 catch( MalformedFieldException mfe ) {
556 mfe.printStackTrace();
557 }
558 }
559
560 /**
561 * Set the animal's weight range and weight units.<br><br>
562 * Stored as OBX with loinc code 3141-9 "Body Weight Measured." This is
563 * just a convenience method for the common case where weights are normally
564 * always measured.
565 * @param sMin std::string with low end of weight range in numeric form
566 * @param sMax std::string with high end of weight range in numeric form
567 * @param sWeightUnits std::string with units in ISO or ANSI abbreviation
568 * (usually kg or lb)
569 */
570 public void setWeightRange( String sMin, String sMax, CEElement ceWeightUnits ) {
571 // Need to construct OBX with appropriate LOINC code for measured or estimated
572 // weight observation.
573 OBXSegment obx = addOBX();
574 obx.setObservationIdentifier( Loinc.BODY_WEIGHT_ESTIMATED.Clone() );
575 try {
576 SNElement snWeightRange = new SNElement();
577 snWeightRange.setComparator( "=" );
578 snWeightRange.setNum1( sMin );
579 snWeightRange.setSeparator( "-" );
580 snWeightRange.setNum2( sMax );
581 obx.setObservationValueType( "SN" );
582 obx.setObservationValue( snWeightRange );
583 obx.setUnits( ceWeightUnits );
584 }
585 catch( MalformedFieldException mfe ) {
586 mfe.printStackTrace();
587 }
588 }
589
590 /**
591 * Get the animal's weight.<br><br>
592 * Stored as OBX with loinc code 8335-2 "Body Weight Estimated" or
593 * 3141-9 "Body Weight Measured"<br>
594 * Note: We assume only one weight. The logic here is to take the first found
595 * of measured or the first estimated if no measured found. Equally valid would be
596 * to take the latest measurement, etc.
597 * @return String with weight
598 */
599 public String getWeight() {
600 String sWeight = "";
601 ORDER_OBSERVATIONLoop loop = getPATIENT_RESULT().getORDER_OBSERVATION();
602 Iterator i = loop.findOBXSegments(Loinc.BODY_WEIGHT_MEASURED);
603 if( i.hasNext() ) {
604 OBXSegment obx = (OBXSegment)i.next();
605 sWeight = obx.getObservationValue().getValue();
606 }
607 else {
608 Iterator i2 = loop.findOBXSegments(Loinc.BODY_WEIGHT_ESTIMATED);
609 if( i2.hasNext() ) {
610 OBXSegment obx = (OBXSegment)i2.next();
611 HL7Element hlE = obx.getObservationValue();
612 if( hlE instanceof SNElement ) {
613 SNElement snE = (SNElement)hlE;
614 sWeight = snE.getValue();
615 }
616 else
617 sWeight = hlE.getValue();
618 }
619
620 }
621 return sWeight;
622 }
623
624 /**
625 * Get the weight units.<br><br>
626 * Note: Thelogic used here must be kept in step with the logic used
627 * in getWeight(). For now that means if there is a measured weight we
628 * use it in getWeight and return true hereWe assume only one weight.
629 * The logic here is to take the first found of measured or the first
630 * estimated if no measured found. Equally valid would be to take the
631 * latest measurement, etc.. Sequential calls to getWeight(), getWeightUnits(),
632 * and getWeightMeasured() should return information about the same
633 * weight observation. This might be un-threadsafe in environments where
634 * another thread could be writing a weight OBX while another is reading.
635 * In such cases, it would be better to get the OBX and extract the fields
636 * manually.<br>
637 * TODO: If demand arises, add a getWeightOBX() method to facilitate thread-safe access.
638 * @return String with weight units in ISO or ANSI abbreviation
639 */
640 public String getWeightUnits() {
641 String sWeightUnits = "";
642 ORDER_OBSERVATIONLoop loop = getPATIENT_RESULT().getORDER_OBSERVATION();
643 Iterator i = loop.findOBXSegments(Loinc.BODY_WEIGHT_MEASURED);
644 if( i.hasNext() ) {
645 OBXSegment obx = (OBXSegment)i.next();
646 sWeightUnits = obx.getUnits().getValue();
647 }
648 else {
649 Iterator i2 = loop.findOBXSegments(Loinc.BODY_WEIGHT_ESTIMATED);
650 if( i2.hasNext() ) {
651 OBXSegment obx = (OBXSegment)i2.next();
652 sWeightUnits = obx.getUnits().getValue();
653 }
654 }
655 return sWeightUnits;
656 }
657
658 /**
659 * Was the weight we returned with getWeight a measured weight rather
660 * than an estimate. <br><br>
661 * Note: Thelogic used here must be kept in step with the logic used
662 * in getWeight(). For now that means if there is a measured weight we
663 * use it in getWeight and return true hereWe assume only one weight.
664 * The logic here is to take the first found of measured or the first
665 * estimated if no measured found. Equally valid would be to take the
666 * latest measurement, etc.. Sequential calls to getWeight(), getWeightUnits(),
667 * and getWeightMeasured() should return information about the same
668 * weight observation. This might be un-thread-safe in environments where
669 * one thread could be writing a weight OBX while another is reading.
670 * In such cases, it would be better to get the OBX and extract the fields
671 * manually.<br>
672 * TODO: If demand arises, add a getWeightOBX() method to facilitate thread-safe access.
673 * @return boolean true if a measured weight found. NOTE: This returns false
674 * even if NO weight observation was found, so this should only be interpreted
675 * after retrieving a valid weight value.
676 */
677 public boolean getWeightMeasured() {
678 boolean bMeasured = false;
679 ORDER_OBSERVATIONLoop loop = getPATIENT_RESULT().getORDER_OBSERVATION();
680 Iterator i = loop.findOBXSegments(Loinc.BODY_WEIGHT_MEASURED);
681 if( i.hasNext() ) {
682 bMeasured = true;
683 }
684 return bMeasured;
685 }
686
687 /**
688 * Set the animal's color as uncoded text.<br><br>
689 * Stored as OBX with loinc code 29552-7 color nar
690 * @param sColor String color
691 */
692 public void setColor( String sColor ) {
693 // Need to construct OBX with appropriate LOINC code for measured or estimated
694 // weight observation.
695 OBXSegment obx = addOBX();
696 obx.setObservationIdentifier( Loinc.COLOR_NAR );
697 try {
698 obx.setObservationValueType( "ST" );
699 obx.setObservationValue( sColor );
700 }
701 catch( MalformedFieldException mfe ) {
702 mfe.printStackTrace();
703 }
704 }
705
706 /**
707 * Get the animal's color as string.<br><br>
708 * Stored as OBX with loinc code 29552-7 color nar
709 * @return String color
710 */
711 public String getColor() {
712 String sColor = "";
713 ORDER_OBSERVATIONLoop loop = getPATIENT_RESULT().getORDER_OBSERVATION();
714 Iterator i = loop.findOBXSegments(Loinc.COLOR_NAR);
715 if( i.hasNext() ) {
716 OBXSegment obx = (OBXSegment)i.next();
717 sColor = obx.getObservationValue().getValue();
718 }
719 return sColor;
720 }
721
722 /**
723 * Set the microchip number and type.
724 * @param sChipNumber String with chip number
725 * @param sChipType String with chip type coded or text?
726 */
727 public void setMicrochip( String sChipNumber, String sChipType ) {
728 if( !Identifiers.isChipType( sChipType ) ) {
729 // Should replace this with more robust error handler.
730 // Real program should use pick list for chip type anyway.
731 System.err.println( "Unknown chip type: " + sChipType );
732 }
733 PIDSegment pid = getPID();
734 boolean bFound = false;
735 // First try to update existing chip entry (why would we ever?)
736 Iterator i = pid.listPatientIds();
737 while( i != null && i.hasNext() ) {
738 CXElement cxe = (CXElement)i.next();
739 // Check assigner logic
740 String sAssigner = cxe.getAssigningAuthorityName();
741 if( sAssigner != null && sAssigner.equals( sChipType ) ) {
742 cxe.setIdentifier( sChipNumber );
743 bFound = true;
744 break;
745 }
746 }
747 // Otherwise add a new identifier
748 if( !bFound ) {
749 pid.addPatientId( sChipNumber, sChipType );
750 }
751 }
752
753 /**
754 * Get the microchip number.<br><br>
755 * Note: This logic assumes only one microchip per animal. It is possible
756 * that an animal would have multiple, ie, one US and one European chip.
757 * More than one chip can be set using this program logic as long as the
758 * types differ. They they will be stored and transmitted correctly and
759 * could be retrieved using lower-level code. However, this code returns only
760 * the first chip found.<br>
761 * Note: The same sort of thread-safety issue exists as in the
762 * {@link #getWeightUnits() getWeightUnits} method.
763 * @return String with chip number
764 */
765 public String getMicrochipNumber() {
766 PIDSegment pid = getPID();
767 // First try to update existing MRN
768 Iterator i = pid.listPatientIds();
769 while( i.hasNext() ) {
770 CXElement cxe = (CXElement)i.next();
771 // Check assigner logic
772 String sAssigner = cxe.getAssigningAuthorityName();
773 if( sAssigner != null && Identifiers.isChipType( sAssigner ) ) {
774 return cxe.getIdentifier();
775 }
776 }
777 return "";
778 }
779
780 /**
781 * Get the microchip type.<br><br>
782 * Note: This logic assumes only one microchip per animal. It is possible
783 * that an animal would have multiple, ie, one US and one European chip.
784 * More than one chip can be set using this program logic as long as the
785 * types differ. They they will be stored and transmitted correctly and
786 * could be retrieved using lower-level code. However, this code returns only
787 * the first chip found.<br>
788 * Note: The same sort of thread-safety issue exists as in the
789 * {@link #getWeightUnits() getWeightUnits} method.
790 * @return String with chip type
791 */
792 public String getMicrochipType() {
793 PIDSegment pid = getPID();
794 // First try to update existing MRN
795 Iterator i = pid.listPatientIds();
796 while( i.hasNext() ) {
797 CXElement cxe = (CXElement)i.next();
798 // Check assigner logic
799 String sAssigner = cxe.getAssigningAuthorityName();
800 if( sAssigner != null && Identifiers.isChipType( sAssigner ) ) {
801 return sAssigner;
802 }
803 }
804 return "";
805 }
806
807 /**
808 * Set the tattoo text and type.<br><br>
809 * Note: This logic assumes only one tattoo per animal. It is possible
810 * that an animal would have multiple. More than one tattoo can be set
811 * using this program logic as long as they are different types and they will
812 * be stored and transmitted correctly.
813 * However, this logic returns only the tattoo found.
814 * @param sTattooText String with text of tattoo
815 * @param sTattooType String with type of tattoo (location, program, etc.) The
816 * value supplied must be one of the constants defined in Identifiers. Eventually
817 * these constants will be replaced with a more robust system for controlled
818 * vocabulary lookup. For now, programmers may add constants to Identifiers,
819 * Loinc, etc., without being <i>required</i> to submit the change under the LGPL.
820 */
821 public void setTattoo( String sTattooText, String sTattooType ) {
822 if( !Identifiers.isTattooType( sTattooType ) ) {
823 // Should replace this with more robust error handler.
824 // Does a finite list of tattoo types make sense the same way microchip types do?
825 System.err.println( "Unknown tattoo type: " + sTattooType );
826 }
827 PIDSegment pid = getPID();
828 boolean bFound = false;
829 // First try to update existing chip entry (why would we ever?)
830 Iterator i = pid.listPatientIds();
831 while( i != null && i.hasNext() ) {
832 CXElement cxe = (CXElement)i.next();
833 // Check assigner logic
834 String sAssigner = cxe.getAssigningAuthorityName();
835 if( sAssigner != null && sAssigner.equals( sTattooType ) ) {
836 cxe.setIdentifier( sTattooText );
837 bFound = true;
838 break;
839 }
840 }
841 // Otherwise add a new identifier
842 if( !bFound ) {
843 pid.addPatientId( sTattooText, sTattooType );
844 }
845 }
846
847 /**
848 * Get the tattoo text.<br><br>
849 * Note: This logic assumes only one tattoo per animal. This method returns
850 * the first found.
851 * However, this logic returns only the tattoo found.<br>
852 * Note: The same sort of thread-safety issue exists as in the
853 * {@link #getWeightUnits() getWeightUnits} method.
854 * @return String with tattoo text
855 */
856 public String getTattooText() {
857 PIDSegment pid = getPID();
858 // First try to update existing MRN
859 Iterator i = pid.listPatientIds();
860 while( i.hasNext() ) {
861 CXElement cxe = (CXElement)i.next();
862 // Check assigner logic
863 String sAssigner = cxe.getAssigningAuthorityName();
864 if( sAssigner != null && Identifiers.isTattooType( sAssigner ) ) {
865 return cxe.getIdentifier();
866 }
867 }
868 return "";
869 }
870
871 /**
872 * Get the tattoo type.<br><br>
873 * Note: This logic assumes only one tattoo per animal. This method returns
874 * the first found.<br>
875 * Note: The same sort of thread-safety issue exists as in the
876 * {@link #getWeightUnits() getWeightUnits} method.
877 * @return String with tattoo type (location, program, etc.)
878 */
879 public String getTattooType() {
880 PIDSegment pid = getPID();
881 // First try to update existing MRN
882 Iterator i = pid.listPatientIds();
883 while( i.hasNext() ) {
884 CXElement cxe = (CXElement)i.next();
885 // Check assigner logic
886 String sAssigner = cxe.getAssigningAuthorityName();
887 if( sAssigner != null && Identifiers.isTattooType( sAssigner ) ) {
888 return sAssigner;
889 }
890 }
891 return "";
892 }
893
894 /**
895 * Set the ear tag text and type.<br><br>
896 * Note: This logic assumes only one ear tag per animal. It is possible
897 * that an animal would have multiple. More than one ear tag can be set
898 * using this program logic as long as they are different types and they will
899 * be stored and transmitted correctly.
900 * However, this logic returns only the first ear tag found.<br>
901 * More so than the other identifiers, this may be an issue. It is not
902 * a big project for the library developer to change to add/list logic but
903 * it will add complexity at the application programming layer as it will
904 * be up to the application to look through the list Iterator.
905 * @param sEarTagText String with text of ear tag
906 * @param sEarTagType String with type of ear tag (location, program, etc.)
907 */
908 public void setEarTag( String sEarTagText, String sEarTagType ) {
909 if( !Identifiers.isEarTagType( sEarTagType ) ) {
910 // Should replace this with more robust error handler.
911 // Real program should use pick list for chip type anyway.
912 System.err.println( "Unknown ear tag type: " + sEarTagType );
913 }
914 PIDSegment pid = getPID();
915 boolean bFound = false;
916 // First try to update existing chip entry (why would we ever?)
917 Iterator i = pid.listPatientIds();
918 while( i != null && i.hasNext() ) {
919 CXElement cxe = (CXElement)i.next();
920 // Check assigner logic
921 String sAssigner = cxe.getAssigningAuthorityName();
922 if( sAssigner != null && sAssigner.equals( sEarTagType ) ) {
923 cxe.setIdentifier( sEarTagText );
924 bFound = true;
925 break;
926 }
927 }
928 // Otherwise add a new identifier
929 if( !bFound ) {
930 pid.addPatientId( sEarTagText, sEarTagType );
931 }
932 }
933
934 /**
935 * Get the ear tag text.<br><br>
936 * Note: This logic assumes only one ear tag per animal. It returns
937 * only the first ear tag found.<br>
938 * Note: The same sort of thread-safety issue exists as in the
939 * {@link #getWeightUnits() getWeightUnits} method.
940 * @return String with ear tag text
941 */
942 public String getEarTagText() {
943 PIDSegment pid = getPID();
944 // First try to update existing MRN
945 Iterator i = pid.listPatientIds();
946 while( i.hasNext() ) {
947 CXElement cxe = (CXElement)i.next();
948 // Check assigner logic
949 String sAssigner = cxe.getAssigningAuthorityName();
950 if( sAssigner != null && Identifiers.isEarTagType( sAssigner ) ) {
951 return cxe.getIdentifier();
952 }
953 }
954 return "";
955 }
956
957 /**
958 * Get the ear tag type.<br><br>
959 * Note: This logic assumes only one ear tag per animal. It returns
960 * only the first ear tag found.<br>
961 * Note: The same sort of thread-safety issue exists as in the
962 * {@link #getWeightUnits() getWeightUnits} method.
963 * @return String with ear tag type
964 */
965 public String getEarTagType() {
966 PIDSegment pid = getPID();
967 // First try to update existing MRN
968 Iterator i = pid.listPatientIds();
969 while( i.hasNext() ) {
970 CXElement cxe = (CXElement)i.next();
971 // Check assigner logic
972 String sAssigner = cxe.getAssigningAuthorityName();
973 if( sAssigner != null && Identifiers.isEarTagType( sAssigner ) ) {
974 return sAssigner;
975 }
976 }
977 return "";
978 }
979
980 /**
981 * Set the postal code of <strong>animal's</strong> residence.
982 * @param sPostalCode String with Zipcode or other postal code
983 */
984 public void setPatientZipcode( String sZipcode ) {
985 PIDSegment pid = getPID();
986 pid.setPatientZipcode( sZipcode );
987 }
988
989 /**
990 * Get the postal code.
991 * @return String with Zipcode or other postal code
992 */
993 public String getPatientZipcode() {
994 PIDSegment pid = getPID();
995 return pid.getPatientZipcode();
996 }
997
998 /**
999 * Set the patient's name (normally "Confidential").
1000 * @param sName String with name
1001 */
1002 public void setPatientName( String sName ) {
1003 PIDSegment pid = getPID();
1004 pid.setPatientName( sName );
1005 }
1006
1007 /**
1008 * Get the patient's name.
1009 * @return String with Name
1010 */
1011 public String getPatientName() {
1012 PIDSegment pid = getPID();
1013 return pid.getPatientNameString();
1014 }
1015
1016 /**
1017 * Set the patient class code (A, I, O, R).<br><br>
1018 * TODO: Add error checking to ensure only valud class code is provided.
1019 * @param sPatientClass String with patient class code
1020 */
1021 public void setPatientClass( String sPatClass ) {
1022 PV1Segment pv1 = getPV1();
1023 pv1.setPatientClass( sPatClass );
1024 }
1025
1026 /**
1027 * Get the patient class code.
1028 * @return String with patient class code
1029 */
1030 public String getPatientClass() {
1031 PV1Segment pv1 = getPV1();
1032 return pv1.getPatientClass();
1033 }
1034
1035 /**
1036 * Set the admission type code (C, K, E, Z, P, or R).<br><br>
1037 * TODO: Add error checking to ensure only valud class code is provided.
1038 * @param sAdmitType String with admission type code
1039 */
1040 public void setAdmissionType( String sAdmissionType ) {
1041 PV1Segment pv1 = getPV1();
1042 pv1.setAdmissionType( sAdmissionType );
1043 }
1044
1045 /**
1046 * Get the admission type code.
1047 * @return String with admission type code
1048 */
1049 public String getAdmissionType() {
1050 PV1Segment pv1 = getPV1();
1051 return pv1.getAdmissionType();
1052 }
1053
1054 /**
1055 * Set the attending doctor.
1056 * @param sIdNumber String Attending Doctor ID
1057 * @param sAssigningAuthority String with identifier of assigning facility
1058 */
1059 public void setAttendingDoctor( String sIdNumber, String sAssigningAuthority ) {
1060 PV1Segment pv1 = getPV1();
1061 pv1.setAttendingDoctorId( sIdNumber );
1062 // Check assigner logic
1063 pv1.setAttendingDoctorAssigningAuthority( sAssigningAuthority );
1064 }
1065
1066 /**
1067 * Set the attending doctor ID number using the default assigning facility
1068 * of the facility sending the report. (As is normal VMDB procedure,)
1069 * @param sIdNumber Attending Doctor identifier assigned by sending facility
1070 */
1071 public void setAttendingDoctorId( String sIdNumber ) {
1072 MSHSegment msh = getMSH();
1073 String sThisFacility = msh.getSendingFacilityName();
1074 setAttendingDoctor( sIdNumber, sThisFacility );
1075 }
1076
1077 /**
1078 * Set the attending doctor.
1079 * @param sAssigningAuthority String with identifier of assigning facility
1080 */
1081 public void setAttendingDoctorAssigningAuthority( String sIdNumber, String sAssigningAuthority ) {
1082 PV1Segment pv1 = getPV1();
1083 // Check assigner logic
1084 pv1.setAttendingDoctorAssigningAuthority( sAssigningAuthority );
1085 }
1086
1087 /**
1088 * Get the attending doctorn ID as a full XCN Element.<br><br>
1089 * Note: This and other "get" methods that return HL7 Element objects return
1090 * references to the object in place in the message. They can thus be used to
1091 * obtain a reference to a newly added entry. The XCNElement object's "set"
1092 * methods can then be used to add details not provided with mutator methods
1093 * at the message level. These additional components will most likely be ignored
1094 * by VMDB when the message is received, but may be useful in other applications of the
1095 * same messages, and as standard HL7 content will not cause errors at VMDB.
1096 * @return Attending doctor's full extended composite name
1097 */
1098 public XCNElement getAttendingDoctor() {
1099 PV1Segment pv1 = getPV1();
1100 return pv1.getAttendingDoctor();
1101 }
1102
1103 /**
1104 * Get the attending doctor ID number.
1105 * @return String with ID number
1106 */
1107 public String getAttendingDoctorId() {
1108 PV1Segment pv1 = getPV1();
1109 return pv1.getAttendingDoctorId();
1110 }
1111
1112 /**
1113 * Get the attending doctor ID assigning facility.<br><br>
1114 * TODO: Check assigner logic and replace with Assigning Authority if
1115 * necessary.
1116 * @return String with identifier of Assigning Facility
1117 */
1118 public String getAttendingDoctorAssigningAuthority() {
1119 PV1Segment pv1 = getPV1();
1120 return pv1.getAttendingDoctorAssigningAuthority();
1121 }
1122
1123 /**
1124 * Set the Visit Number.<br><br>
1125 * Normally assigned by the sending facility so this
1126 * is added as the default Assigning Faciltiy.
1127 * @param sVisitNumber String with facility-assigned visit identifier
1128 */
1129 public void setVisitNumber( String sVisitNumber ) {
1130 MSHSegment msh = getMSH();
1131 String sThisFacility = msh.getSendingFacilityName();
1132 PV1Segment pv1 = getPV1();
1133 pv1.setVisitNumberId( sVisitNumber );
1134 // Check assigner logic
1135 pv1.setVisitNumberAssigningAuthority( sThisFacility );
1136 }
1137
1138 /**
1139 * Set the Visit Number ID assigning facility.<br><br>
1140 * Note: setVisitNumber() automatically assigns thisFacility as the assigning
1141 * facility. So use only setVisitNumberAssigningAuthority() after setting
1142 * the number to override on those <i>rare</i> occasions when sending for a
1143 * subsidiary, etc., with a different identifier than the sender.<br>
1144 * TODO: Check assigner logic and replace with Assigning Authority if
1145 * necessary.
1146 * @param sAssigningAuthority String with namespace identifier for assigning facility
1147 */
1148 public void setVisitNumberAssigningAuthority( String sAssigningAuthority ) {
1149 PV1Segment pv1 = getPV1();
1150 pv1.setVisitNumberAssigningAuthority( sAssigningAuthority );
1151 }
1152
1153 /**
1154 * Get the Visit Number ID as full CX Element.
1155 * @return CXElement with visit number
1156 */
1157 public CXElement getVisitNumber() {
1158 PV1Segment pv1 = getPV1();
1159 return pv1.getVisitNumber();
1160 }
1161
1162 /**
1163 * Get the Visit Number ID number.
1164 * @return String with Visit ID number
1165 */
1166 public String getVisitNumberId() {
1167 PV1Segment pv1 = getPV1();
1168 return pv1.getVisitNumberId();
1169 }
1170
1171 /**
1172 * Get the Visit Number assigning facility.<br><br>
1173 * TODO: Check assigner logic and replace with Assigning Authority if
1174 * necessary.
1175 * @return String with authority namespace id
1176 */
1177 public String getVisitNumberAssigningAuthority() {
1178 PV1Segment pv1 = getPV1();
1179 return pv1.getVisitNumberAssigningAuthority();
1180 }
1181
1182 /**
1183 * Set the Discharge Disposition.<br><br>
1184 * TODO: Add code validation logic
1185 * @param sDisp one character string [0,1,2, or 3] for alive,
1186 * dead, euthanized, or referred
1187 */
1188 public void setDisposition( String sDisp ) {
1189 PV1Segment pv1 = getPV1();
1190 pv1.setDisposition( sDisp );
1191 }
1192
1193 /**
1194 * Get Discharge Disposition string.
1195 * @return String with discharge disposition code
1196 */
1197 public String getDisposition() {
1198 PV1Segment pv1 = getPV1();
1199 return pv1.getDisposition();
1200 }
1201
1202
1203 /**
1204 * Set the admit date/time of the message to string formatted date/time.<br><br>
1205 * TODO: Add date format validation logic
1206 * @param sDateTime String with date/time in yyyyMMddHHmmss format
1207 *
1208 */
1209 public void setAdmitDateTime( String sDateTime ) {
1210 PV1Segment pv1 = getPV1();
1211 pv1.setAdmitDateTime( sDateTime );
1212 }
1213
1214 /**
1215 * Get the admit date/time as a string.
1216 * @return String date/time
1217 */
1218 public String getAdmitDateTime() {
1219 PV1Segment pv1 = getPV1();
1220 return pv1.getAdmitDateTime();
1221 }
1222
1223 /**
1224 * Set the discharge date/time of the message to string formatted date/time.<br><br>
1225 * TODO: Add date format validation logic
1226 * @param sDateTime String with date/time in yyyyMMddHHmmss format
1227 *
1228 */
1229 public void setDischargeDateTime( String sDateTime ) {
1230 PV1Segment pv1 = getPV1();
1231 pv1.setDischargeDateTime( sDateTime );
1232 }
1233
1234 /**
1235 * Get the discharge date/time as a string.
1236 * @return String date/time in yyyyMMddHHmmss format
1237 */
1238 public String getDischargeDateTime() {
1239 PV1Segment pv1 = getPV1();
1240 return pv1.getDischargeDateTime();
1241 }
1242
1243
1244 /**
1245 * Set the Order Control.<br><br>
1246 * TODO: Add code validation logic
1247 * @param sOrder Control NW, CA, RP, or RO,
1248 */
1249 public void setOrderControl( String sOrderControl ) {
1250 ORCSegment orc = getORC();
1251 orc.setOrderControl( sOrderControl );
1252 }
1253
1254 /**
1255 * Get Order Contrl string.
1256 * @return String with discharge disposition code
1257 */
1258 public String getOrderControl() {
1259 ORCSegment orc = getORC();
1260 return orc.getOrderControl();
1261 }
1262
1263 /**
1264 * Set the coded universal service identifier.<br><br>
1265 * This version takes the fully qualified CEElement components
1266 * @param sCode code value normally snomed
1267 * @param sText spelled out term
1268 * @param sSystem normally SCT
1269 */
1270 public void setUniversalServiceId( String sCode, String sText, String sCodeType ) {
1271 CEElement ceE = new CEElement( sCode, sText, sCodeType );
1272 OBRSegment obr = getOBR();
1273 obr.setUniversalServiceId(ceE);
1274 }
1275
1276 /**
1277 * Set the coded universal service identifier as a preformed CE Element.<br><br>
1278 * Note: For VMDB submissions this will always be called as <br>
1279 * <code>setUniversalServiceId( Loinc.CHART_ABSTRACT );</code><br>
1280 * If we can figure out where to put it, we may make this a default. The
1281 * problem with that would be confusion when used for other applications.
1282 * @param ceServiceId CEElement preformed usually constant from LOINC or SNOMED
1283 */
1284 public void setUniversalServiceId( CEElement ceServiceId ) {
1285 OBRSegment obr = getOBR();
1286 obr.setUniversalServiceId(ceServiceId);
1287 }
1288
1289 /**
1290 * Get the coded universal service identifier as a preformed CE Element.
1291 * @return A reference to a CEElement with the Universal Service ID.
1292 * Normally a preformed usually constant from LOINC or SNOMED
1293 */
1294 public CEElement getUniversalServiceId() {
1295 OBRSegment obr = getOBR();
1296 return obr.getUniversalServiceId();
1297 }
1298
1299 /**
1300 * Get the universal service identifier text.
1301 * @return String text of the type of service "requested." In VMDB submissions
1302 * this is always "Chart Abstract"
1303 */
1304 public String getUniversalServiceIdText() {
1305 OBRSegment obr = getOBR();
1306 return obr.getUniversalServiceIdText();
1307 }
1308
1309
1310 /**
1311 * Set the observation date/time of the message to string formatted date/time.
1312 * @param sDateTime String with date/time in yyyyMMddHHmmss format
1313 */
1314 public void setObservationDateTime( String sDateTime ) {
1315 OBRSegment obr = getOBR();
1316 obr.setObservationDateTime( sDateTime );
1317 }
1318
1319 /**
1320 * Get the observation date/time as a string.
1321 * @return String date/time
1322 */
1323 public String getObservationDateTime() {
1324 OBRSegment obr = getOBR();
1325 return obr.getObservationDateTime();
1326 }
1327
1328 /**
1329 * Modify a coded OBXSegment using predefined Coded Entry for identifier and code.<br><br>
1330 * Often uses one of the set of predefined constants.<br>
1331 * The same Modifier methods can be used for Complaints, Diagnoses, Procedures, Findings, etc.,
1332 * anything in a coded OBX.<br>
1333 * This logic uses the SubId field value. Each root observation within a GRP_1
1334 * loop receives a unique integer SubId. Modifiers of that root receive the root's
1335 * integer followed by a period and a sequential integer. Modifiers of modifiers
1336 * similarly add another period and integer.<br>
1337 * TODO: Get the correct nomenclature for ceIdentifier and adjust method and
1338 * documentation accordingly.
1339 * @param obxRoot The OBXSegment to which modifier is applied. Used to
1340 * obtain SubId value for this segment.
1341 * @param ceIdentifier CEElement using predefined snomed code for type of
1342 * modification such as "with associated etiology" or "with laterality."
1343 * @param ceModifier CEElement populated with modifier term.
1344 */
1345 public OBXSegment modifyObservation( OBXSegment obxRoot,
1346 CEElement ceIdentifier,
1347 CEElement ceModifier ) {
1348 ORDER_OBSERVATIONLoop loop = getPATIENT_RESULT().getORDER_OBSERVATION();
1349 String sSubId = loop.nextModifierSubId( obxRoot );
1350 // Don't allow automatic assignment of top-level subId
1351 OBXSegment obx = loop.addOBX( sSubId );
1352 obx.setObservationIdentifier( ceIdentifier );
1353 try {
1354 obx.setObservationValueType( "CE" );
1355 obx.setObservationValue( ceModifier );
1356 }
1357 catch( MalformedFieldException mfe ) {
1358 mfe.printStackTrace();
1359 }
1360 return obx;
1361 }
1362
1363 /**
1364 * Get the Modifier list as iterator over {@link org.vmdb.hl7.OBXSegment OBXSegment} objects.<br><br>
1365 * The implementation is going to be very Java-specific because it depends on garbage collection
1366 * to maintain an instance of a Vector until Iterator is released.
1367 * @param obxRoot The OBXSegment to which modifiers are applied. Used to
1368 * obtain subId value for this segment. This does not need to be a root-level
1369 * diagnosis, finding, etc.. It can be itself a modifier. It simply indicates the
1370 * observation being modified by the modifiers returned. Similarly, modifiers of
1371 * these modifiers are not returned. To retrieve them, call listModifiers again
1372 * passign each of the OBXs in the iterator in turn. To retrieve all modifiers
1373 * that affect this observation directly or indirectly, you would perform a
1374 * depth-first recursive tree walk, but that--as they say--is an excercise left
1375 * to the student.
1376 * @return Iterator over collection of {@link org.vmdb.hl7.OBXSegment OBXSegment}
1377 * objects that modify the root OBX.
1378 */
1379 public Iterator listModifiers( OBXSegment obxRoot ) {
1380 ORDER_OBSERVATIONLoop loop = getPATIENT_RESULT().getORDER_OBSERVATION();
1381 Iterator i = loop.findOBXModifiers( obxRoot );
1382 return i;
1383 }
1384
1385 /**
1386 * Set the Chief Complaint as a predefined CE Element.
1387 * Often uses one of the set of predefined constants.
1388 * @param ceChiefComplaint CEElement populated with Chief Complaint
1389 * @return OBXSegment just added. This is normally used
1390 * to apply modifiers if needed.
1391 */
1392 public OBXSegment setChiefComplaint( CEElement ceChiefComplaint ) {
1393 OBXSegment obx = addOBX();
1394 obx.setObservationIdentifier( Loinc.CHIEF_COMPLAINT_NOM );
1395 try {
1396 obx.setObservationValueType( "CE" );
1397 obx.setObservationValue( ceChiefComplaint );
1398 }
1399 catch( MalformedFieldException mfe ) {
1400 mfe.printStackTrace();
1401 }
1402 return obx;
1403 }
1404
1405 /**
1406 * Set the Chief Complaint as the individual components of a CE Element.
1407 * @param sChiefComplaintCode String snomed code for Chief Complaint
1408 * @param sChiefComplaintText String Chief Complaint spelled out
1409 * @param sCodeSystem String, usually SCT, with type of code
1410 * @return OBXSegment just added. This is normally used
1411 * to apply modifiers if needed.
1412 */
1413 public OBXSegment setChiefComplaint( String sChiefComplaintCode,
1414 String sChiefComplaintText,
1415 String sCodeSystem ) {
1416 // Need to construct OBX with appropriate LOINC code for measured or estimated
1417 // weight observation.
1418 OBXSegment obx = addOBX();
1419 obx.setObservationIdentifier( Loinc.CHIEF_COMPLAINT_NOM );
1420 CEElement ceE = new CEElement();
1421 try {
1422 ceE.setIdentifier( sChiefComplaintCode );
1423 ceE.setText( sChiefComplaintText );
1424 ceE.setCodingSystem( sCodeSystem );
1425 obx.setObservationValueType( "CE" );
1426 obx.setObservationValue( ceE );
1427 }
1428 catch( MalformedFieldException mfe ) {
1429 mfe.printStackTrace();
1430 }
1431 return obx;
1432 }
1433
1434 /**
1435 * Set the Chief Complaint as the individual components of a CE Element.
1436 * @param sChiefComplaintCode String snomed code for Chief Complaint
1437 * @param sChiefComplaintText String Chief Complaint spelled out
1438 * @param sCodeSystem String, usually SCT, with type of code
1439 * @param sAltChiefComplaintCode String alternate code for the SAME Chief Complaint
1440 * @param sAltChiefComplaintText String Chief Complaint spelled out as in alternate system
1441 * @param sAltCodeSystem String, alternate type of code
1442 * @return OBXSegment just added. This is normally used
1443 * to apply modifiers if needed.
1444 */
1445 public OBXSegment setChiefComplaint( String sChiefComplaintCode,
1446 String sChiefComplaintText,
1447 String sCodeSystem ,
1448 String sAltChiefComplaintCode,
1449 String sAltChiefComplaintText,
1450 String sAltCodeSystem) {
1451 // Need to construct OBX with appropriate LOINC code for measured or estimated
1452 // weight observation.
1453 OBXSegment obx = addOBX();
1454 obx.setObservationIdentifier( Loinc.CHIEF_COMPLAINT_NOM );
1455 CEElement ceE = new CEElement();
1456 try {
1457 ceE.setIdentifier( sChiefComplaintCode );
1458 ceE.setText( sChiefComplaintText );
1459 ceE.setCodingSystem( sCodeSystem );
1460 ceE.setAltIdentifier( sAltChiefComplaintCode );
1461 ceE.setAltText( sAltChiefComplaintText );
1462 ceE.setAltCodingSystem( sAltCodeSystem );
1463 obx.setObservationValueType( "CE" );
1464 obx.setObservationValue( ceE );
1465 }
1466 catch( MalformedFieldException mfe ) {
1467 mfe.printStackTrace();
1468 }
1469 return obx;
1470 }
1471
1472 /**
1473 * Get the Chief Complaint as a predefined CE Element.<br><br>
1474 * Often uses one of the set of predefined constants.
1475 * @return CEElement populated with ChiefComplaint
1476 */
1477 public CEElement getChiefComplaint() {
1478 CEElement ceChiefComplaint = null;
1479 ORDER_OBSERVATIONLoop loop = getPATIENT_RESULT().getORDER_OBSERVATION();
1480 Iterator i = loop.findOBXSegments( Loinc.CHIEF_COMPLAINT_NOM );
1481 if( i.hasNext() ) {
1482 OBXSegment obx = (OBXSegment)i.next();
1483 if( obx.getObservationValueType().equals( "CE" ) ) {
1484 ceChiefComplaint = (CEElement)obx.getObservationValue();
1485 }
1486 else { // For now we'll assume it is a simple type. If not, we'll get the whole HL7
1487 ceChiefComplaint = new CEElement();
1488 ceChiefComplaint.setText( obx.getObservationValue().getValue() );
1489 }
1490 }
1491 return ceChiefComplaint;
1492 }
1493
1494 /**
1495 * Get the Chief Complaint text.
1496 * @return String ChiefComplaint spelled out
1497 */
1498 public String getChiefComplaintText() {
1499 CEElement ceChiefComplaint = getChiefComplaint();
1500 if( ceChiefComplaint == null ) return "";
1501 return ceChiefComplaint.getText();
1502 }
1503
1504 /**
1505 * Add a Diagnosis as a predefined CE Element.<br><br>
1506 * Often uses one of the set of predefined constants
1507 * @param ceDiagnosis CEElement populated with the coded Diagnosis
1508 * @return OBXSegment just added. This is normally used
1509 * to apply modifiers if needed.
1510 */
1511 public OBXSegment addDiagnosis( CEElement ceDiagnosis ) {
1512 return addDiagnosis( ceDiagnosis, false );
1513 }
1514
1515 /**
1516 * Add a Diagnosis as a predefined CE Element.<br><br>
1517 * Often uses one of the set of predefined constants
1518 * @param ceDiagnosis CEElement populated with the coded Diagnosis
1519 * @param bRecheck true if this diagnosis is a recheck (default false)
1520 * @return OBXSegment just added. This is normally used
1521 * to apply modifiers if needed.
1522 */
1523 public OBXSegment addDiagnosis( CEElement ceDiagnosis, boolean bRecheck ) {
1524 OBXSegment obx = addOBX();
1525 if( bRecheck )
1526 obx.setObservationIdentifier( Loinc.RECHECK_NOM );
1527 else
1528 obx.setObservationIdentifier( Loinc.DIAGNOSIS_NOM );
1529 try {
1530 obx.setObservationValueType( "CE" );
1531 obx.setObservationValue( ceDiagnosis );
1532 }
1533 catch( MalformedFieldException mfe ) {
1534 mfe.printStackTrace();
1535 }
1536 return obx;
1537 }
1538
1539 /**
1540 * Add a Diagnosis as the individual components of the CE Element.
1541 * @param sDiagnosisCode String snomed code for the Diagnosis
1542 * @param sDiagnosisText String with the Diagnosis spelled out
1543 * @param sCodeSystem String, usually "SCT," with the type of code used
1544 * @param bRecheck true if this diagnosis is a recheck (default false)
1545 * @return OBXSegment just added. This is normally used
1546 * to apply modifiers if needed.
1547 */
1548 public OBXSegment addDiagnosis( String sDiagnosisCode,
1549 String sDiagnosisText,
1550 String sCodeSystem ) {
1551 return addDiagnosis( sDiagnosisCode, sDiagnosisText, sCodeSystem, false );
1552 }
1553
1554 /**
1555 * Add a Diagnosis as the individual components of the CE Element.
1556 * @param sDiagnosisCode String snomed code for the Diagnosis
1557 * @param sDiagnosisText String with the Diagnosis spelled out
1558 * @param sCodeSystem String, usually "SCT," with the type of code used
1559 * @param sAltDiagnosisCode String alternate code for the Diagnosis
1560 * @param sAltDiagnosisText String with the Diagnosis spelled out as in alternate system
1561 * @param sAltCodeSystem String, alternate type of code used
1562 * @param bRecheck true if this diagnosis is a recheck (default false)
1563 * @return OBXSegment just added. This is normally used
1564 * to apply modifiers if needed.
1565 */
1566 public OBXSegment addDiagnosis( String sDiagnosisCode,
1567 String sDiagnosisText,
1568 String sCodeSystem,
1569 String sAltDiagnosisCode,
1570 String sAltDiagnosisText,
1571 String sAltCodeSystem ) {
1572 return addDiagnosis( sDiagnosisCode, sDiagnosisText, sCodeSystem,
1573 sAltDiagnosisCode, sAltDiagnosisText, sAltCodeSystem, false );
1574 }
1575
1576 /**
1577 * Add a Diagnosis as the individual components of the CE Element.
1578 * @param sDiagnosisCode String snomed code for the Diagnosis
1579 * @param sDiagnosisText String with the Diagnosis spelled out
1580 * @param sCodeSystem String, usually "SCT," with the type of code used
1581 * @param bRecheck true if this diagnosis is a recheck (default false)
1582 * @return OBXSegment just added. This is normally used
1583 * to apply modifiers if needed.
1584 */
1585 public OBXSegment addDiagnosis( String sDiagnosisCode,
1586 String sDiagnosisText,
1587 String sCodeSystem,
1588 boolean bRecheck ) {
1589 OBXSegment obx = addOBX();
1590 if( bRecheck )
1591 obx.setObservationIdentifier( Loinc.RECHECK_NOM );
1592 else
1593 obx.setObservationIdentifier( Loinc.DIAGNOSIS_NOM );
1594 CEElement ceE = new CEElement();
1595 try {
1596 ceE.setIdentifier( sDiagnosisCode );
1597 ceE.setText( sDiagnosisText );
1598 ceE.setCodingSystem( sCodeSystem );
1599 obx.setObservationValueType( "CE" );
1600 obx.setObservationValue( ceE );
1601 }
1602 catch( MalformedFieldException mfe ) {
1603 mfe.printStackTrace();
1604 }
1605 return obx;
1606 }
1607
1608 /**
1609 * Add a Diagnosis as the individual components of the CE Element.
1610 * @param sDiagnosisCode String snomed code for the Diagnosis
1611 * @param sDiagnosisText String with the Diagnosis spelled out
1612 * @param sCodeSystem String, usually "SCT," with the type of code used
1613 * @param sAltDiagnosisCode String alternate code for the Diagnosis
1614 * @param sAltDiagnosisText String with the Diagnosis spelled out as in alternate system
1615 * @param sAltCodeSystem String, Alternate coding system
1616 * @param bRecheck true if this diagnosis is a recheck (default false)
1617 * @return OBXSegment just added. This is normally used
1618 * to apply modifiers if needed.
1619 */
1620 public OBXSegment addDiagnosis( String sDiagnosisCode,
1621 String sDiagnosisText,
1622 String sCodeSystem,
1623 String sAltDiagnosisCode,
1624 String sAltDiagnosisText,
1625 String sAltCodeSystem,
1626 boolean bRecheck ) {
1627 OBXSegment obx = addOBX();
1628 if( bRecheck )
1629 obx.setObservationIdentifier( Loinc.RECHECK_NOM );
1630 else
1631 obx.setObservationIdentifier( Loinc.DIAGNOSIS_NOM );
1632 CEElement ceE = new CEElement();
1633 try {
1634 ceE.setIdentifier( sDiagnosisCode );
1635 ceE.setText( sDiagnosisText );
1636 ceE.setCodingSystem( sCodeSystem );
1637 ceE.setAltIdentifier( sAltDiagnosisCode );
1638 ceE.setAltText( sAltDiagnosisText );
1639 ceE.setAltCodingSystem( sAltCodeSystem );
1640 obx.setObservationValueType( "CE" );
1641 obx.setObservationValue( ceE );
1642 }
1643 catch( MalformedFieldException mfe ) {
1644 mfe.printStackTrace();
1645 }
1646 return obx;
1647 }
1648
1649 /**
1650 * Get the Diagnosis list as an iterator over {@link org.vmdb.hl7.OBXSegment OBXSegment} objects.<br><br>
1651 * Often uses one of the set of predefined constants.<br>
1652 * The implementation is going to be very Java-specific because it depends on garbage collection
1653 * to maintain an instance of a Vector until Iterator is released.
1654 * @return Iterator over collection
1655 * of {@link org.vmdb.hl7.OBXSegment OBXSegment} objects from Diagnosis OBXs
1656 */
1657 public Iterator listDiagnoses() {
1658 ORDER_OBSERVATIONLoop loop = getPATIENT_RESULT().getORDER_OBSERVATION();
1659 Iterator i = loop.findOBXSegments( Loinc.DIAGNOSIS_NOM );
1660 return i;
1661 }
1662
1663 /**
1664 * Get the Recheck list as an iterator over {@link org.vmdb.hl7.OBXSegment OBXSegment} objects.<br><br>
1665 * Often uses one of the set of predefined constants.<br>
1666 * The implementation is going to be very Java-specific because it depends on garbage collection
1667 * to maintain an instance of a Vector until Iterator is released.
1668 * @return Iterator over collection
1669 * of {@link org.vmdb.hl7.OBXSegment OBXSegment} objects from Recheck OBXs
1670 */
1671 public Iterator listRechecks() {
1672 ORDER_OBSERVATIONLoop loop = getPATIENT_RESULT().getORDER_OBSERVATION();
1673 Iterator i = loop.findOBXSegments( Loinc.RECHECK_NOM );
1674 return i;
1675 }
1676
1677 /**
1678 * Add a Procedure as a predefined CE Element.<br><br>
1679 * Often uses one of the set of predefined constants
1680 * @param ceProcedure CEElement populated with the coded Procedure
1681 * @return OBXSegment just added. This is normally used
1682 * to apply modifiers if needed.
1683 */
1684 public OBXSegment addProcedure( CEElement ceProcedure ) {
1685 OBXSegment obx = addOBX();
1686 obx.setObservationIdentifier( Loinc.PROCEDURE_TYPE );
1687 try {
1688 obx.setObservationValueType( "CE" );
1689 obx.setObservationValue( ceProcedure );
1690 }
1691 catch( MalformedFieldException mfe ) {
1692 mfe.printStackTrace();
1693 }
1694 return obx;
1695 }
1696
1697 /**
1698 * Add a Procedure as the individual components of a CE Element.
1699 * @param sProcedureCode String with the code for Procedure
1700 * @param sProcedureText String with the Procedure spelled out
1701 * @param sCodeSystem String, usually "SCT," with the type of code
1702 * @return OBXSegment just added. This is normally used
1703 * to apply modifiers if needed.
1704 */
1705 public OBXSegment addProcedure( String sProcedureCode,
1706 String sProcedureText,
1707 String sCodeSystem ) {
1708 OBXSegment obx = addOBX();
1709 obx.setObservationIdentifier( Loinc.PROCEDURE_TYPE );
1710 CEElement ceE = new CEElement();
1711 try {
1712 ceE.setIdentifier( sProcedureCode );
1713 ceE.setText( sProcedureText );
1714 ceE.setCodingSystem( sCodeSystem );
1715 obx.setObservationValueType( "CE" );
1716 obx.setObservationValue( ceE );
1717 }
1718 catch( MalformedFieldException mfe ) {
1719 mfe.printStackTrace();
1720 }
1721 return obx;
1722 }
1723
1724 /**
1725 * Add a Procedure as the individual components of a CE Element.
1726 * @param sProcedureCode String with the code for Procedure
1727 * @param sProcedureText String with the Procedure spelled out
1728 * @param sCodeSystem String, usually "SCT," with the type of code
1729 * @param sAltProcedureCode String alternate code for the SAME Procedure
1730 * @param sAltProcedureText String with the Procedure spelled out as in the alternate system
1731 * @param sAltCodeSystem String, alternate type of code
1732 * @return OBXSegment just added. This is normally used
1733 * to apply modifiers if needed.
1734 */
1735 public OBXSegment addProcedure( String sProcedureCode,
1736 String sProcedureText,
1737 String sCodeSystem ,
1738 String sAltProcedureCode,
1739 String sAltProcedureText,
1740 String sAltCodeSystem) {
1741 OBXSegment obx = addOBX();
1742 obx.setObservationIdentifier( Loinc.PROCEDURE_TYPE );
1743 CEElement ceE = new CEElement();
1744 try {
1745 ceE.setIdentifier( sProcedureCode );
1746 ceE.setText( sProcedureText );
1747 ceE.setCodingSystem( sCodeSystem );
1748 ceE.setAltIdentifier( sAltProcedureCode );
1749 ceE.setAltText( sAltProcedureText );
1750 ceE.setAltCodingSystem( sAltCodeSystem );
1751 obx.setObservationValueType( "CE" );
1752 obx.setObservationValue( ceE );
1753 }
1754 catch( MalformedFieldException mfe ) {
1755 mfe.printStackTrace();
1756 }
1757 return obx;
1758 }
1759
1760 /**
1761 * Get the Procedure list as an iterator over {@link org.vmdb.hl7.OBXSegment OBXSegment} objects.<br><br>
1762 * Often uses one of the set of predefined constants.<br>
1763 * The implementation is going to be very Java-specific because it depends on garbage collection
1764 * to maintain an instance of a Vector until Iterator is released.
1765 * @return Iterator over collection of {@link org.vmdb.hl7.OBXSegment OBXSegment} objects from Procedure OBXs
1766 */
1767 public Iterator listProcedures() {
1768 ORDER_OBSERVATIONLoop loop = getPATIENT_RESULT().getORDER_OBSERVATION();
1769 Iterator i = loop.findOBXSegments( Loinc.PROCEDURE_TYPE );
1770 return i;
1771 }
1772
1773 /**
1774 * Add a Finding as a predefined CE Element.<br><br>
1775 * Often uses one of the set of predefined constants
1776 * @param ceFinding CEElement populated with the coded Finding
1777 * @return OBXSegment just added. This is normally used
1778 * to apply modifiers if needed.
1779 */
1780 public OBXSegment addFinding( CEElement ceFinding ) {
1781 OBXSegment obx = addOBX();
1782 obx.setObservationIdentifier( Loinc.FINDINGS_NOM );
1783 try {
1784 obx.setObservationValueType( "CE" );
1785 obx.setObservationValue( ceFinding );
1786 }
1787 catch( MalformedFieldException mfe ) {
1788 mfe.printStackTrace();
1789 }
1790 return obx;
1791 }
1792
1793 /**
1794 * Add a Finding as the individual components of a CE Element.
1795 * @param sFindingCode String with the code for Finding
1796 * @param sFindingText String with the Finding spelled out
1797 * @param sCodeSystem String, usually "SCT," with the type of code used
1798 * @return OBXSegment just added. This is normally used
1799 * to apply modifiers if needed.
1800 */
1801 public OBXSegment addFinding( String sFindingCode,
1802 String sFindingText,
1803 String sCodeSystem ) {
1804 OBXSegment obx = addOBX();
1805 obx.setObservationIdentifier( Loinc.FINDINGS_NOM );
1806 CEElement ceE = new CEElement();
1807 try {
1808 ceE.setIdentifier( sFindingCode );
1809 ceE.setText( sFindingText );
1810 ceE.setCodingSystem( sCodeSystem );
1811 obx.setObservationValueType( "CE" );
1812 obx.setObservationValue( ceE );
1813 }
1814 catch( MalformedFieldException mfe ) {
1815 mfe.printStackTrace();
1816 }
1817 return obx;
1818 }
1819
1820 /**
1821 * Add a Finding as the individual components of a CE Element.
1822 * @param sFindingCode String with the code for Finding
1823 * @param sFindingText String with the Finding spelled out
1824 * @param sCodeSystem String, usually "SCT," with the type of code used
1825 * @param sAltFindingCode String alternate code for the SAME Finding
1826 * @param sAltFindingText String with the Finding spelled out
1827 * @param sAltCodeSystem String, aternate type of code used
1828 * @return OBXSegment just added. This is normally used
1829 * to apply modifiers if needed.
1830 */
1831 public OBXSegment addFinding( String sFindingCode,
1832 String sFindingText,
1833 String sCodeSystem ,
1834 String sAltFindingCode,
1835 String sAltFindingText,
1836 String sAltCodeSystem) {
1837 OBXSegment obx = addOBX();
1838 obx.setObservationIdentifier( Loinc.FINDINGS_NOM );
1839 CEElement ceE = new CEElement();
1840 try {
1841 ceE.setIdentifier( sFindingCode );
1842 ceE.setText( sFindingText );
1843 ceE.setCodingSystem( sCodeSystem );
1844 ceE.setAltIdentifier( sAltFindingCode );
1845 ceE.setAltText( sAltFindingText );
1846 ceE.setAltCodingSystem( sAltCodeSystem );
1847 obx.setObservationValueType( "CE" );
1848 obx.setObservationValue( ceE );
1849 }
1850 catch( MalformedFieldException mfe ) {
1851 mfe.printStackTrace();
1852 }
1853 return obx;
1854 }
1855
1856 /**
1857 * Get the Finding list as an iterator over {@link org.vmdb.hl7.OBXSegment OBXSegment} objects.<br><br>
1858 * Often uses one of the set of predefined constants.<br>
1859 * The implementation is going to be very Java-specific because it depends on garbage collection
1860 * to maintain an instance of a Vector until Iterator is released.
1861 * @return Iterator over collection
1862 * of {@link org.vmdb.hl7.OBXSegment OBXSegment} objects from Finding OBXs
1863 */
1864 public Iterator listFindings() {
1865 ORDER_OBSERVATIONLoop loop = getPATIENT_RESULT().getORDER_OBSERVATION();
1866 Iterator i = loop.findOBXSegments( Loinc.FINDINGS_NOM );
1867 return i;
1868 }
1869
1870 } // end class ORUMessage
1871