001package org.hl7.fhir.convertors.loaders.loaderR5;
002
003import java.io.FileInputStream;
004import java.io.IOException;
005import java.io.InputStream;
006import java.util.ArrayList;
007import java.util.HashSet;
008import java.util.List;
009import java.util.Set;
010import java.util.UUID;
011
012/*
013  Copyright (c) 2011+, HL7, Inc.
014  All rights reserved.
015  
016  Redistribution and use in source and binary forms, with or without modification, 
017  are permitted provided that the following conditions are met:
018    
019   * Redistributions of source code must retain the above copyright notice, this 
020     list of conditions and the following disclaimer.
021   * Redistributions in binary form must reproduce the above copyright notice, 
022     this list of conditions and the following disclaimer in the documentation 
023     and/or other materials provided with the distribution.
024   * Neither the name of HL7 nor the names of its contributors may be used to 
025     endorse or promote products derived from this software without specific 
026     prior written permission.
027  
028  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
029  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
030  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
031  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
032  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
033  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
034  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
035  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
036  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
037  POSSIBILITY OF SUCH DAMAGE.
038  
039 */
040
041
042import org.hl7.fhir.convertors.advisors.impl.BaseAdvisor_40_50;
043import org.hl7.fhir.convertors.factory.VersionConvertorFactory_40_50;
044import org.hl7.fhir.convertors.txClient.TerminologyClientFactory;
045import org.hl7.fhir.exceptions.FHIRException;
046import org.hl7.fhir.r4.formats.JsonParser;
047import org.hl7.fhir.r4.formats.XmlParser;
048import org.hl7.fhir.r4.model.Basic;
049import org.hl7.fhir.r4.model.Resource;
050import org.hl7.fhir.r5.conformance.StructureDefinitionHacker;
051import org.hl7.fhir.r5.context.IContextResourceLoader;
052import org.hl7.fhir.r5.context.SimpleWorkerContext.PackageResourceLoader;
053import org.hl7.fhir.r5.model.Bundle;
054import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent;
055import org.hl7.fhir.r5.model.Bundle.BundleType;
056import org.hl7.fhir.r5.model.CanonicalResource;
057import org.hl7.fhir.r5.model.CodeSystem;
058import org.hl7.fhir.r5.model.StructureDefinition;
059import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
060import org.hl7.fhir.r5.terminologies.client.TerminologyClientManager.ITerminologyClientFactory;
061import org.hl7.fhir.r5.utils.R5Hacker;
062import org.hl7.fhir.utilities.Utilities;
063import org.hl7.fhir.utilities.filesystem.ManagedFileAccess;
064
065public class R4ToR5Loader extends BaseLoaderR5 implements IContextResourceLoader {
066
067  private final BaseAdvisor_40_50 advisor = new BaseAdvisor_40_50();
068  private String version;
069
070  public R4ToR5Loader(Set<String> types, ILoaderKnowledgeProviderR5 lkp, String version) { // might be 4B
071    super(types, lkp);
072    this.version = version;
073  }
074
075  @Override
076  public Bundle loadBundle(InputStream stream, boolean isJson) throws FHIRException, IOException {
077    Resource r4 = null;
078    if (isJson)
079      r4 = new JsonParser().parse(stream);
080    else
081      r4 = new XmlParser().parse(stream);
082    org.hl7.fhir.r5.model.Resource r5 = VersionConvertorFactory_40_50.convertResource(r4, advisor);
083
084    Bundle b;
085    if (r5 instanceof Bundle)
086      b = (Bundle) r5;
087    else {
088      b = new Bundle();
089      b.setId(UUID.randomUUID().toString().toLowerCase());
090      b.setType(BundleType.COLLECTION);
091      b.addEntry().setResource(r5).setFullUrl(r5 instanceof CanonicalResource ? ((CanonicalResource) r5).getUrl() : null);
092    }
093    for (CodeSystem cs : advisor.getCslist()) {
094      BundleEntryComponent be = b.addEntry();
095      be.setFullUrl(cs.getUrl());
096      be.setResource(cs);
097    }
098    if (killPrimitives) {
099      List<BundleEntryComponent> remove = new ArrayList<BundleEntryComponent>();
100      for (BundleEntryComponent be : b.getEntry()) {
101        if (be.hasResource() && be.getResource() instanceof StructureDefinition) {
102          StructureDefinition sd = (StructureDefinition) be.getResource();
103          if (sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE)
104            remove.add(be);
105        }
106      }
107      b.getEntry().removeAll(remove);
108    }
109    if (patchUrls) {
110      for (BundleEntryComponent be : b.getEntry()) {
111        if (be.hasResource()) {
112          inspectResource(be.getResource());
113          doPatchUrls(be.getResource());
114        }
115      }
116    }
117    return b;
118  }
119
120  @Override
121  public org.hl7.fhir.r5.model.Resource loadResource(InputStream stream, boolean isJson) throws FHIRException, IOException {
122    Resource r4 = null;
123    if (isJson)
124      r4 = new JsonParser().parse(stream);
125    else
126      r4 = new XmlParser().parse(stream);
127    org.hl7.fhir.r5.model.Resource r5 = VersionConvertorFactory_40_50.convertResource(r4);
128    setPath(r5);
129
130    if (!advisor.getCslist().isEmpty()) {
131      throw new FHIRException("Error: Cannot have included code systems");
132    }
133    if (killPrimitives) {
134      throw new FHIRException("Cannot kill primitives when using deferred loading");
135    }
136    if (r5 instanceof StructureDefinition) {
137      r5 = new StructureDefinitionHacker(version).fixSD((StructureDefinition) r5);
138    }
139    inspectResource(r5);
140    if (patchUrls) {
141      doPatchUrls(r5);
142    }
143    return r5;
144  }
145
146  
147  @Override
148  public List<CodeSystem> getCodeSystems() {
149    return new ArrayList<>();
150  }
151
152  @Override
153  protected String versionString() {
154    return "4.0";
155  }
156
157
158  @Override
159  public ITerminologyClientFactory txFactory() {
160    return new TerminologyClientFactory(versionString());
161  }
162
163  @Override
164  public Set<String> reviewActualTypes(Set<String> types) {
165    Set<String> set = new HashSet<String>();
166    for (String t : types) {
167      if (Utilities.existsInList(t, "ActorDefinition", "Requirements", "SubscriptionTopic", "TestPlan")) {
168        set.add("Basic");
169      } else {
170        set.add(t);
171      }      
172    }    
173    return set;
174  }
175
176  @Override
177  public PackageResourceLoader editInfo(PackageResourceLoader pri) {
178    if (pri.getType().equals("Basic")) {
179      try {
180        InputStream f = pri.getStream();
181        try {
182          Basic b = (Basic) new JsonParser().parse(f);
183          org.hl7.fhir.r5.model.Resource r5 = VersionConvertorFactory_40_50.convertResource(b);
184          if (r5 instanceof CanonicalResource) {
185            pri.setResource((CanonicalResource) r5);
186            pri.updateInfo();
187            setPath(r5);
188          } else {
189            return null;
190          }
191        } finally {
192          f.close();
193        }
194      } catch (Exception e) {
195        throw new FHIRException("Error loading Resource Basic/"+pri.getId()+": "+e.getMessage(), e);
196      }
197    }
198    return pri;
199  }
200}