001package org.hl7.fhir.convertors;
002
003import java.io.IOException;
004
005/*
006  Copyright (c) 2011+, HL7, Inc.
007  All rights reserved.
008  
009  Redistribution and use in source and binary forms, with or without modification, 
010  are permitted provided that the following conditions are met:
011    
012   * Redistributions of source code must retain the above copyright notice, this 
013     list of conditions and the following disclaimer.
014   * Redistributions in binary form must reproduce the above copyright notice, 
015     this list of conditions and the following disclaimer in the documentation 
016     and/or other materials provided with the distribution.
017   * Neither the name of HL7 nor the names of its contributors may be used to 
018     endorse or promote products derived from this software without specific 
019     prior written permission.
020  
021  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
022  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
023  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
024  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
025  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
026  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
027  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
028  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
029  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
030  POSSIBILITY OF SUCH DAMAGE.
031  
032 */
033import org.hl7.fhir.convertors.factory.VersionConvertorFactory_10_30;
034import org.hl7.fhir.convertors.factory.VersionConvertorFactory_10_40;
035import org.hl7.fhir.convertors.factory.VersionConvertorFactory_14_30;
036import org.hl7.fhir.convertors.factory.VersionConvertorFactory_14_40;
037import org.hl7.fhir.convertors.factory.VersionConvertorFactory_30_40;
038import org.hl7.fhir.exceptions.FHIRException;
039import org.hl7.fhir.r4.elementmodel.Manager.FhirFormat;
040import org.hl7.fhir.r4.formats.IParser.OutputStyle;
041import org.hl7.fhir.r4.model.FhirPublication;
042
043public class VersionConversionService {
044  /**
045   * use the package manager to load relevant conversion packages, and then initialise internally as required
046   * <p>
047   * not thread safe
048   *
049   * @param system   - true if the software is running in system context, not in a user context
050   * @param txServer - Address of the terminology server to use (null = use http://tx.fhir.org
051   */
052  public VersionConversionService(boolean system, String txServer) throws FHIRException {
053
054  }
055
056  /**
057   * convert from one version to another.
058   * <p>
059   * This routine is thread safe
060   *
061   * @param src        - the resource to convert
062   * @param srcVersion - the version of the resource to convert
063   * @param dstVersion - the target version to convert to
064   * @return the converted resource
065   * @throws FHIRException - if the source resource cannot be parsed, no single path exists from source to dest version, or the conversion process fails
066   * @throws IOException
067   */
068  public byte[] convert(byte[] src, FhirFormat srcFormat, FhirPublication srcVersion, FhirFormat dstFormat, FhirPublication dstVersion, boolean useJava, OutputStyle style) throws FHIRException, IOException {
069    if (src == null)
070      throw new FHIRException("No source specified");
071    if (srcVersion == null)
072      throw new FHIRException("No source version specified");
073    if (dstVersion == null)
074      throw new FHIRException("No destination version specified");
075    switch (srcVersion) {
076      case DSTU1:
077        throw new FHIRException("FHIR Version #1 is not supported by the inter-version convertor");
078      case DSTU2:
079        return convert10(parseResource10(src, srcFormat), dstFormat, dstVersion, useJava, style);
080      case DSTU2016May:
081        return convert14(parseResource14(src, srcFormat), dstFormat, dstVersion, useJava, style);
082      case R4:
083        return convert40(parseResource40(src, srcFormat), dstFormat, dstVersion, useJava, style);
084      case STU3:
085        return convert30(parseResource30(src, srcFormat), dstFormat, dstVersion, useJava, style);
086      default:
087        throw new FHIRException("FHIR Version 'unknown' is not supported by the inter-version convertor");
088    }
089  }
090
091  private org.hl7.fhir.dstu2.model.Resource parseResource10(byte[] src, FhirFormat srcFormat) throws FHIRException, IOException {
092    switch (srcFormat) {
093      case JSON:
094        return new org.hl7.fhir.dstu2.formats.JsonParser().parse(src);
095      case TEXT:
096        throw new FHIRException("Text format not supported for DSTU2");
097      case TURTLE:
098        throw new FHIRException("Turtle format not supported for DSTU2");
099      case VBAR:
100        throw new FHIRException("Vertical Bar format not supported for DSTU2");
101      case XML:
102        return new org.hl7.fhir.dstu2.formats.XmlParser().parse(src);
103      default:
104        throw new FHIRException("Unknown format not supported for DSTU2");
105    }
106  }
107
108  private org.hl7.fhir.dstu2016may.model.Resource parseResource14(byte[] src, FhirFormat srcFormat) throws FHIRException, IOException {
109    switch (srcFormat) {
110      case JSON:
111        return new org.hl7.fhir.dstu2016may.formats.JsonParser().parse(src);
112      case TEXT:
113        throw new FHIRException("Text format not supported for DSTU2");
114      case TURTLE:
115        throw new FHIRException("Turtle format not supported for DSTU2");
116      case VBAR:
117        throw new FHIRException("Vertical Bar format not supported for DSTU2");
118      case XML:
119        return new org.hl7.fhir.dstu2016may.formats.XmlParser().parse(src);
120      default:
121        throw new FHIRException("Unknown format not supported for DSTU2");
122    }
123  }
124
125  private org.hl7.fhir.dstu3.model.Resource parseResource30(byte[] src, FhirFormat srcFormat) throws FHIRException, IOException {
126    switch (srcFormat) {
127      case JSON:
128        return new org.hl7.fhir.dstu3.formats.JsonParser().parse(src);
129      case TEXT:
130        throw new FHIRException("Text format not supported for DSTU2");
131      case TURTLE:
132        return new org.hl7.fhir.dstu3.formats.RdfParser().parse(src);
133      case VBAR:
134        throw new FHIRException("Vertical Bar format not supported for DSTU2");
135      case XML:
136        return new org.hl7.fhir.dstu3.formats.XmlParser().parse(src);
137      default:
138        throw new FHIRException("Unknown format not supported for DSTU2");
139    }
140  }
141
142  private org.hl7.fhir.r4.model.Resource parseResource40(byte[] src, FhirFormat srcFormat) throws FHIRException, IOException {
143    switch (srcFormat) {
144      case JSON:
145        return new org.hl7.fhir.r4.formats.JsonParser().parse(src);
146      case TEXT:
147        throw new FHIRException("Text format not supported for DSTU2");
148      case TURTLE:
149        return new org.hl7.fhir.r4.formats.RdfParser().parse(src);
150      case VBAR:
151        throw new FHIRException("Vertical Bar format not supported for DSTU2");
152      case XML:
153        return new org.hl7.fhir.r4.formats.XmlParser().parse(src);
154      default:
155        throw new FHIRException("Unknown format not supported for DSTU2");
156    }
157  }
158
159  private org.hl7.fhir.dstu2.formats.IParser.OutputStyle style10(OutputStyle style) {
160    return style == OutputStyle.CANONICAL ? org.hl7.fhir.dstu2.formats.IParser.OutputStyle.CANONICAL : style == OutputStyle.NORMAL ? org.hl7.fhir.dstu2.formats.IParser.OutputStyle.NORMAL : org.hl7.fhir.dstu2.formats.IParser.OutputStyle.PRETTY;
161  }
162
163  private org.hl7.fhir.dstu2016may.formats.IParser.OutputStyle style14(OutputStyle style) {
164    return style == OutputStyle.CANONICAL ? org.hl7.fhir.dstu2016may.formats.IParser.OutputStyle.CANONICAL : style == OutputStyle.NORMAL ? org.hl7.fhir.dstu2016may.formats.IParser.OutputStyle.NORMAL : org.hl7.fhir.dstu2016may.formats.IParser.OutputStyle.PRETTY;
165  }
166
167  private org.hl7.fhir.dstu3.formats.IParser.OutputStyle style30(OutputStyle style) {
168    return style == OutputStyle.CANONICAL ? org.hl7.fhir.dstu3.formats.IParser.OutputStyle.CANONICAL : style == OutputStyle.NORMAL ? org.hl7.fhir.dstu3.formats.IParser.OutputStyle.NORMAL : org.hl7.fhir.dstu3.formats.IParser.OutputStyle.PRETTY;
169  }
170
171  private byte[] saveResource10(org.hl7.fhir.dstu2.model.Resource src, FhirFormat dstFormat, OutputStyle style) throws FHIRException, IOException {
172    switch (dstFormat) {
173      case JSON:
174        return new org.hl7.fhir.dstu2.formats.JsonParser().setOutputStyle(style10(style)).composeBytes(src);
175      case TEXT:
176        throw new FHIRException("Text format not supported for DSTU2");
177      case TURTLE:
178        throw new FHIRException("Turtle format not supported for DSTU2");
179      case VBAR:
180        throw new FHIRException("Vertical Bar format not supported for DSTU2");
181      case XML:
182        return new org.hl7.fhir.dstu2.formats.XmlParser().setOutputStyle(style10(style)).composeBytes(src);
183      default:
184        throw new FHIRException("Unknown format not supported for DSTU2");
185    }
186  }
187
188  private byte[] saveResource14(org.hl7.fhir.dstu2016may.model.Resource src, FhirFormat dstFormat, OutputStyle style) throws FHIRException, IOException {
189    switch (dstFormat) {
190      case JSON:
191        return new org.hl7.fhir.dstu2016may.formats.JsonParser().setOutputStyle(style14(style)).composeBytes(src);
192      case TEXT:
193        throw new FHIRException("Text format not supported for DSTU2");
194      case TURTLE:
195        throw new FHIRException("Turtle format not supported for DSTU2");
196      case VBAR:
197        throw new FHIRException("Vertical Bar format not supported for DSTU2");
198      case XML:
199        return new org.hl7.fhir.dstu2016may.formats.XmlParser().setOutputStyle(style14(style)).composeBytes(src);
200      default:
201        throw new FHIRException("Unknown format not supported for DSTU2");
202    }
203  }
204
205  private byte[] saveResource30(org.hl7.fhir.dstu3.model.Resource src, FhirFormat dstFormat, OutputStyle style) throws FHIRException, IOException {
206    switch (dstFormat) {
207      case JSON:
208        return new org.hl7.fhir.dstu3.formats.JsonParser().setOutputStyle(style30(style)).composeBytes(src);
209      case TEXT:
210        throw new FHIRException("Text format not supported for DSTU2");
211      case TURTLE:
212        return new org.hl7.fhir.dstu3.formats.RdfParser().setOutputStyle(style30(style)).composeBytes(src);
213      case VBAR:
214        throw new FHIRException("Vertical Bar format not supported for DSTU2");
215      case XML:
216        return new org.hl7.fhir.dstu3.formats.XmlParser().setOutputStyle(style30(style)).composeBytes(src);
217      default:
218        throw new FHIRException("Unknown format not supported for DSTU2");
219    }
220  }
221
222
223  private byte[] saveResource40(org.hl7.fhir.r4.model.Resource src, FhirFormat dstFormat, OutputStyle style) throws FHIRException, IOException {
224    switch (dstFormat) {
225      case JSON:
226        return new org.hl7.fhir.r4.formats.JsonParser().setOutputStyle(style).composeBytes(src);
227      case TEXT:
228        throw new FHIRException("Text format not supported for DSTU2");
229      case TURTLE:
230        return new org.hl7.fhir.r4.formats.RdfParser().setOutputStyle(style).composeBytes(src);
231      case VBAR:
232        throw new FHIRException("Vertical Bar format not supported for DSTU2");
233      case XML:
234        return new org.hl7.fhir.r4.formats.XmlParser().setOutputStyle(style).composeBytes(src);
235      default:
236        throw new FHIRException("Unknown format not supported for DSTU2");
237    }
238  }
239
240
241  private byte[] convert10(org.hl7.fhir.dstu2.model.Resource src, FhirFormat dstFormat, FhirPublication dstVersion, boolean useJava, OutputStyle style) throws FHIRException, IOException {
242    switch (dstVersion) {
243      case DSTU1:
244        throw new FHIRException("FHIR Version #1 is not supported by the inter-version convertor");
245      case DSTU2:
246        return saveResource10(src, dstFormat, style);
247      case DSTU2016May:
248        throw new FHIRException("Conversion from DSTU2 to 2016May version is not supported");
249      case R4:
250        if (useJava && VersionConvertorFactory_10_40.convertsResource(src.fhirType()))
251          return saveResource40(VersionConvertorFactory_10_40.convertResource(src), dstFormat, style); // todo: handle code system?
252        else
253          throw new FHIRException("Conversion from R4 to 2016May version is not supported for resources of type " + src.fhirType());
254      case STU3:
255        if (useJava && VersionConvertorFactory_10_30.convertsResource(src.fhirType()))
256          return saveResource30(VersionConvertorFactory_10_30.convertResource(src), dstFormat, style); // todo: handle code system?
257        else
258          throw new FHIRException("todo: use script based conversion....");
259      default:
260        throw new FHIRException("FHIR Version 'unknown' is not supported by the inter-version convertor");
261    }
262  }
263
264  private byte[] convert14(org.hl7.fhir.dstu2016may.model.Resource src, FhirFormat dstFormat, FhirPublication dstVersion, boolean useJava, OutputStyle style) throws FHIRException, IOException {
265    switch (dstVersion) {
266      case DSTU1:
267        throw new FHIRException("FHIR Version #1 is not supported by the inter-version convertor");
268      case DSTU2:
269        throw new FHIRException("Conversion from 2016May version to DSTU2 is not supported");
270      case DSTU2016May:
271        return saveResource14(src, dstFormat, style);
272      case R4:
273        if (useJava && VersionConvertorFactory_14_40.convertsResource(src.fhirType()))
274          return saveResource40(VersionConvertorFactory_14_40.convertResource(src), dstFormat, style);
275        else
276          throw new FHIRException("Conversion from 2016May version to R4 is not supported for resources of type " + src.fhirType());
277      case STU3:
278        if (useJava && VersionConvertorFactory_14_30.convertsResource(src.fhirType()))
279          return saveResource30(VersionConvertorFactory_14_30.convertResource(src), dstFormat, style);
280        else
281          throw new FHIRException("Conversion from 2016May version to STU3 is not supported for resources of type " + src.fhirType());
282      default:
283        throw new FHIRException("FHIR Version 'unknown' is not supported by the inter-version convertor");
284    }
285  }
286
287  private byte[] convert30(org.hl7.fhir.dstu3.model.Resource src, FhirFormat dstFormat, FhirPublication dstVersion, boolean useJava, OutputStyle style) throws FHIRException, IOException {
288    switch (dstVersion) {
289      case DSTU1:
290        throw new FHIRException("FHIR Version #1 is not supported by the inter-version convertor");
291      case DSTU2:
292        if (useJava && VersionConvertorFactory_10_30.convertsResource(src.fhirType()))
293          return saveResource10(VersionConvertorFactory_10_30.convertResource(src), dstFormat, style); // todo: handle code system?
294        else
295          throw new FHIRException("todo: use script based conversion....");
296      case DSTU2016May:
297        if (useJava && VersionConvertorFactory_14_30.convertsResource(src.fhirType()))
298          return saveResource14(VersionConvertorFactory_14_30.convertResource(src), dstFormat, style);
299        else
300          throw new FHIRException("Conversion from R3 to 2016May version is not supported for resources of type " + src.fhirType());
301      case R4:
302        if (useJava && VersionConvertorFactory_30_40.convertsResource(src.fhirType()))
303          return saveResource40(VersionConvertorFactory_30_40.convertResource(src), dstFormat, style);
304        else
305          throw new FHIRException("todo: use script based conversion....");
306      case STU3:
307        return saveResource30(src, dstFormat, style);
308      default:
309        throw new FHIRException("FHIR Version 'unknown' is not supported by the inter-version convertor");
310    }
311  }
312
313  private byte[] convert40(org.hl7.fhir.r4.model.Resource src, FhirFormat dstFormat, FhirPublication dstVersion, boolean useJava, OutputStyle style) throws FHIRException, IOException {
314    switch (dstVersion) {
315      case DSTU1:
316        throw new FHIRException("FHIR Version #1 is not supported by the inter-version convertor");
317      case DSTU2:
318        if (useJava && VersionConvertorFactory_10_40.convertsResource(src.fhirType()))
319          return saveResource10(VersionConvertorFactory_10_40.convertResource(src), dstFormat, style); // todo: handle code system?
320        else
321          throw new FHIRException("Conversion from R4 to DSTU2 version is not supported for resources of type " + src.fhirType());
322      case DSTU2016May:
323        if (useJava && VersionConvertorFactory_14_40.convertsResource(src.fhirType()))
324          return saveResource14(VersionConvertorFactory_14_40.convertResource(src), dstFormat, style);
325        else
326          throw new FHIRException("Conversion from DSTU2 to 2016May version is not supported for resources of type " + src.fhirType());
327      case R4:
328        return saveResource40(src, dstFormat, style);
329      case STU3:
330        if (useJava && VersionConvertorFactory_30_40.convertsResource(src.fhirType()))
331          return saveResource30(VersionConvertorFactory_30_40.convertResource(src), dstFormat, style);
332        else
333          throw new FHIRException("todo: use script based conversion....");
334      default:
335        throw new FHIRException("FHIR Version 'unknown' is not supported by the inter-version convertor");
336    }
337  }
338
339}