View Javadoc
1   /*
2    * Copyright 2012 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.openehealth.ipf.commons.ihe.xds.core.metadata;
17  
18  import ca.uhn.hl7v2.HL7Exception;
19  import ca.uhn.hl7v2.Location;
20  import ca.uhn.hl7v2.model.*;
21  import ca.uhn.hl7v2.model.v25.datatype.HD;
22  import ca.uhn.hl7v2.model.v25.message.ACK;
23  import ca.uhn.hl7v2.parser.PipeParser;
24  import org.apache.commons.lang3.StringUtils;
25  import org.apache.commons.lang3.Validate;
26  
27  import javax.xml.bind.annotation.XmlTransient;
28  import java.io.Serializable;
29  
30  /**
31   * An XDS model object backed up by an HL7 v2 element.
32   * @param <C>
33   *     HAPI composite type which corresponds to the HL7 v2 element.
34   *
35   * @author Dmytro Rud
36   */
37  @XmlTransient
38  abstract public class Hl7v2Based<C extends Composite> implements Serializable {
39      private static final long serialVersionUID = 5463666004063275303L;
40  
41      protected static final Message MESSAGE;
42      static {
43          MESSAGE = new ACK();
44          MESSAGE.getParser().getParserConfiguration().setValidating(false);
45      }
46  
47  
48      private final C hapiObject;
49  
50  
51      /**
52       * Default constructor, for serialization purposes only.
53       */
54      protected Hl7v2Based() {
55          throw new IllegalStateException("this default constructor is defined only to satisfy JAXB requirements");
56      }
57  
58  
59      /**
60       * Constructor.
61       * @param hapiObject
62       *      HAPI composite object.
63       */
64      protected Hl7v2Based(C hapiObject) {
65          this.hapiObject = Validate.notNull(hapiObject, "HAPI object");
66      }
67  
68  
69      /**
70       * Parses the given HL7 v2 element into an XDS simplified model object.
71       * @param hl7String
72       *      HL7 v2 element as a String.
73       * @param xdsModelClass
74       *      class of the XDS model object to be generates.
75       * @param <C>
76       *      class of HAPI composite object which should hold the HL7 element.
77       * @param <T>
78       *      class of XDS model object.
79       * @return
80       *      generated XDS model object or <code>null</code> when the given
81       *      HL7 v2 element is <code>null</code> or empty.
82       */
83      public static <C extends Composite, T extends Hl7v2Based<C>> T parse(
84              String hl7String,
85              Class<T> xdsModelClass)
86      {
87          if (StringUtils.isEmpty(hl7String)) {
88              return null;
89          }
90  
91          try {
92              T xdsModelObject = xdsModelClass.newInstance();
93              MESSAGE.getParser().parse(xdsModelObject.getHapiObject(), hl7String, XdsHl7v2Renderer.ENCODING_CHARACTERS);
94              return xdsModelObject.isEmpty() ? null : xdsModelObject;
95          } catch (InstantiationException | IllegalAccessException | HL7Exception e) {
96              throw new RuntimeException(e);
97          }
98      }
99  
100 
101     /**
102      * Renders this XDS model object using the XDS-specific
103      * {@link XdsHl7v2Renderer HL7 v2 renderer},
104      * i.e. with applying IHE TF rules regarding unwanted components.
105      * @return
106      *      HL7 v2 representation of this XDS model object, may be an empty String.
107      */
108     protected String render() {
109         return XdsHl7v2Renderer.encode(this);
110     }
111 
112 
113     /**
114      * Renders the given XDS model object as an HL7 v2 element according to the
115      * XDS specification, i.e. with applying IHE TF rules regarding unwanted components.
116      *
117      * @param xdsModelObject
118      *      XDS model object.
119      * @return
120      *      HL7 v2 representation of the given object, or <code>null</code>
121      *      when the given object is <code>null</code> or empty.
122      */
123     public static String render(Hl7v2Based xdsModelObject) {
124         return (xdsModelObject != null) ? StringUtils.trimToNull(xdsModelObject.render()) : null;
125     }
126 
127 
128     /**
129      * Renders the given XDS model object as an HL7 v2 element
130      * without applying IHE TF rules regarding unwanted components.
131      *
132      * @param xdsModelObject
133      *      XDS model object.
134      * @return
135      *      HL7 v2 representation of the given object, or an empty string
136      *      when the given object is <code>null</code> or empty.
137      */
138     public static String rawRender(Hl7v2Based xdsModelObject) {
139         return (xdsModelObject != null)
140                 ? PipeParser.encode(xdsModelObject.getHapiObject(), XdsHl7v2Renderer.ENCODING_CHARACTERS)
141                 : "";
142     }
143 
144 
145     /**
146      * @return
147      *      <code>true</code> if this XDS model object does not contain any usable data.
148      */
149     public boolean isEmpty() {
150         return XdsHl7v2Renderer.isEmpty(this);
151     }
152 
153 
154     /**
155      * @return
156      *      HAPI composite holding the HL7 v2 element
157      *      which corresponds to this XDS model object.
158      */
159     public C getHapiObject() {
160         return hapiObject;
161     }
162 
163 
164     protected static void setValue(Primitive p, String value) {
165         if (value == null) {
166             p.clear();
167         } else {
168             try {
169                 p.setValue(value);
170             } catch (DataTypeException e) {
171                 throw new RuntimeException(e);
172             }
173         }
174     }
175 
176     protected static void setValue(Primitive p, Integer value) {
177         setValue(p, (value == null) ? null : value.toString());
178     }
179 
180     protected static Integer getIntegerValue(Primitive p) {
181         String value = p.getValue();
182         return (StringUtils.isEmpty(value) || "\"\"".equals(value)) ? null : new Integer(value);
183     }
184 
185     protected static Long getLongValue(Primitive p) {
186         String value = p.getValue();
187         return (StringUtils.isEmpty(value) || "\"\"".equals(value)) ? null : new Long(value);
188     }
189 
190     /**
191      * Helper method used for copying data elements of an assigning authority.
192      * @param assigningAuthority
193      *      source assigning authority.
194      * @param target
195      *      target HL7 v2 HD element.
196      */
197     protected static void setAssigningAuthority(AssigningAuthority assigningAuthority, HD target) {
198         if (assigningAuthority != null) {
199             HD source = assigningAuthority.getHapiObject().getInternal();
200             setValue(target.getHd1_NamespaceID(), source.getHd1_NamespaceID().getValue());
201             setValue(target.getHd2_UniversalID(), source.getHd2_UniversalID().getValue());
202             setValue(target.getHd3_UniversalIDType(), source.getHd3_UniversalIDType().getValue());
203         } else {
204             target.clear();
205         }
206     }
207 
208 
209     /**
210      * Fake enclosing element for an HL7 v2 sub-component, necessary for correct rendering and parsing.
211      */
212     static class Holder<T extends Type> extends AbstractType implements Composite {
213         private static final long serialVersionUID = -9084300955263787034L;
214 
215         private Type[] data = new Type[1];
216 
217         public Holder(T t) {
218             super(t.getMessage());
219             data[0] = t;
220         }
221 
222         @SuppressWarnings("unchecked")
223         public T getInternal() {
224             return (T) data[0];
225         }
226 
227         @Override
228         public Type[] getComponents() {
229             return this.data;
230         }
231 
232         @Override
233         public Type getComponent(int number) throws DataTypeException {
234             try {
235                 return data[number];
236             } catch (ArrayIndexOutOfBoundsException e) {
237                 throw new DataTypeException("please do not use this class");
238             }
239         }
240 
241         @Override
242         public boolean accept(MessageVisitor visitor, Location currentLocation) throws HL7Exception {
243             return false;
244         }
245     }
246 
247 }