001package org.hl7.fhir.convertors.misc;
002
003import com.google.common.base.Charsets;
004import com.google.gson.JsonArray;
005import com.google.gson.JsonObject;
006import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
007import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
008import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
009import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
010import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
011import org.hl7.fhir.convertors.advisors.impl.BaseAdvisor_30_40;
012import org.hl7.fhir.convertors.advisors.impl.BaseAdvisor_30_50;
013import org.hl7.fhir.convertors.factory.*;
014import org.hl7.fhir.utilities.TextFile;
015import org.hl7.fhir.utilities.VersionUtilities;
016import org.hl7.fhir.utilities.json.JSONUtil;
017import org.hl7.fhir.utilities.json.JsonTrackingParser;
018import org.hl7.fhir.utilities.npm.NpmPackageIndexBuilder;
019
020import java.io.BufferedOutputStream;
021import java.io.ByteArrayOutputStream;
022import java.io.FileInputStream;
023import java.io.IOException;
024import java.nio.charset.StandardCharsets;
025import java.util.ArrayList;
026import java.util.HashMap;
027import java.util.List;
028import java.util.Map;
029import java.util.Map.Entry;
030
031public class NpmPackageVersionConverter {
032
033  private static final int BUFFER_SIZE = 1024;
034
035  private final String source;
036  private final String dest;
037  private final String version;
038  private final String vCode;
039  private final List<String> errors = new ArrayList<>();
040  private String currentVersion;
041
042  public NpmPackageVersionConverter(String source, String dest, String version) {
043    super();
044    this.source = source;
045    this.dest = dest;
046    this.vCode = version;
047    this.version = VersionUtilities.versionFromCode(version);
048  }
049
050  public static void main(String[] args) throws IOException {
051    NpmPackageVersionConverter self = new NpmPackageVersionConverter(args[0], args[1], args[2]);
052    self.execute();
053    System.out.println("Finished");
054    for (String s : self.errors) {
055      System.out.println(s);
056    }
057  }
058
059  public List<String> getErrors() {
060    return errors;
061  }
062
063  public void execute() throws IOException {
064    GzipCompressorInputStream gzipIn;
065    try {
066      gzipIn = new GzipCompressorInputStream(new FileInputStream(source));
067    } catch (Exception e) {
068      throw new IOException("Error reading " + source + ": " + e.getMessage(), e);
069    }
070    Map<String, byte[]> content = new HashMap<>();
071
072    try (TarArchiveInputStream tarIn = new TarArchiveInputStream(gzipIn)) {
073      TarArchiveEntry entry;
074
075      while ((entry = (TarArchiveEntry) tarIn.getNextEntry()) != null) {
076        String n = entry.getName();
077        if (!entry.isDirectory()) {
078          int count;
079          byte[] data = new byte[BUFFER_SIZE];
080          ByteArrayOutputStream fos = new ByteArrayOutputStream();
081          try (BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER_SIZE)) {
082            while ((count = tarIn.read(data, 0, BUFFER_SIZE)) != -1) {
083              dest.write(data, 0, count);
084            }
085          }
086          fos.close();
087          content.put(n, fos.toByteArray());
088        }
089      }
090    }
091
092    Map<String, byte[]> output = new HashMap<>();
093    output.put("package/package.json", convertPackage(content.get("package/package.json")));
094
095    for (Entry<String, byte[]> e : content.entrySet()) {
096      if (!e.getKey().equals("package/package.json")) {
097        byte[] cnv = e.getValue();
098        try {
099          JsonObject json = JsonTrackingParser.parseJson(e.getValue());
100          if (json.has("resourceType")) {
101            cnv = convertResource(e.getKey(), e.getValue());
102          }
103        } catch (Exception ex) {
104        }
105        if (cnv != null && cnv.length > 0) {
106          output.put(e.getKey(), cnv);
107        }
108      }
109    }
110
111    TarArchiveOutputStream tar;
112    ByteArrayOutputStream OutputStream;
113    BufferedOutputStream bufferedOutputStream;
114    GzipCompressorOutputStream gzipOutputStream;
115
116    OutputStream = new ByteArrayOutputStream();
117    bufferedOutputStream = new BufferedOutputStream(OutputStream);
118    gzipOutputStream = new GzipCompressorOutputStream(bufferedOutputStream);
119    tar = new TarArchiveOutputStream(gzipOutputStream);
120
121
122    Map<String, NpmPackageIndexBuilder> indexers = new HashMap<>();
123    for (Entry<String, byte[]> e : output.entrySet()) {
124      String n = e.getKey().substring(0, e.getKey().lastIndexOf("/"));
125      String s = e.getKey().substring(n.length() + 1);
126      byte[] b = e.getValue();
127      NpmPackageIndexBuilder indexer = indexers.get(n);
128      if (indexer == null) {
129        indexer = new NpmPackageIndexBuilder();
130        indexer.start();
131        indexers.put(n, indexer);
132      }
133      indexer.seeFile(s, b);
134      if (!s.equals(".index.json") && !s.equals("package.json")) {
135        TarArchiveEntry entry = new TarArchiveEntry(e.getKey());
136        entry.setSize(b.length);
137        tar.putArchiveEntry(entry);
138        tar.write(b);
139        tar.closeArchiveEntry();
140      }
141    }
142    for (Entry<String, NpmPackageIndexBuilder> e : indexers.entrySet()) {
143      byte[] cnt = e.getValue().build().getBytes(StandardCharsets.UTF_8);
144      TarArchiveEntry entry = new TarArchiveEntry(e.getKey() + "/.index.json");
145      entry.setSize(cnt.length);
146      tar.putArchiveEntry(entry);
147      tar.write(cnt);
148      tar.closeArchiveEntry();
149    }
150
151    byte[] cnt = output.get("package/package.json");
152    TarArchiveEntry entry = new TarArchiveEntry("package/package.json");
153    entry.setSize(cnt.length);
154    tar.putArchiveEntry(entry);
155    tar.write(cnt);
156    tar.closeArchiveEntry();
157
158    tar.finish();
159    tar.close();
160    gzipOutputStream.close();
161    bufferedOutputStream.close();
162    OutputStream.close();
163    byte[] b = OutputStream.toByteArray();
164    TextFile.bytesToFile(b, dest);
165  }
166
167  private byte[] convertPackage(byte[] cnt) throws IOException {
168    JsonObject json = JsonTrackingParser.parseJson(cnt);
169    currentVersion = json.getAsJsonArray("fhirVersions").get(0).getAsString();
170    String name = JSONUtil.str(json, "name");
171    json.remove("name");
172    json.addProperty("name", name + "." + vCode);
173    json.remove("fhirVersions");
174    json.remove("dependencies");
175    JsonArray fv = new JsonArray();
176    json.add("fhirVersions", fv);
177    fv.add(version);
178    JsonObject dep = new JsonObject();
179    json.add("dependencies", dep);
180    dep.addProperty(VersionUtilities.packageForVersion(version), version);
181    return JsonTrackingParser.write(json).getBytes(Charsets.UTF_8);
182  }
183
184  private byte[] convertResource(String n, byte[] cnt) {
185    try {
186      if (VersionUtilities.isR2Ver(currentVersion)) {
187        org.hl7.fhir.dstu2.model.Resource res = new org.hl7.fhir.dstu2.formats.JsonParser().parse(cnt);
188        if (VersionUtilities.isR2Ver(version)) {
189          return new org.hl7.fhir.dstu2.formats.JsonParser().composeBytes(res);
190        } else if (VersionUtilities.isR2BVer(version)) {
191          return new org.hl7.fhir.dstu2016may.formats.JsonParser().composeBytes(VersionConvertorFactory_14_30.convertResource(VersionConvertorFactory_10_30.convertResource(res)));
192        } else if (VersionUtilities.isR3Ver(version)) {
193          return new org.hl7.fhir.dstu3.formats.JsonParser().composeBytes(VersionConvertorFactory_10_30.convertResource(res));
194        } else if (VersionUtilities.isR4Ver(version)) {
195          return new org.hl7.fhir.r4.formats.JsonParser().composeBytes(VersionConvertorFactory_10_40.convertResource(res));
196        } else if (VersionUtilities.isR5Ver(version)) {
197          return new org.hl7.fhir.r5.formats.JsonParser().composeBytes(VersionConvertorFactory_10_50.convertResource(res));
198        }
199      } else if (VersionUtilities.isR2BVer(currentVersion)) {
200        org.hl7.fhir.dstu2016may.model.Resource res = new org.hl7.fhir.dstu2016may.formats.JsonParser().parse(cnt);
201        if (VersionUtilities.isR2Ver(version)) {
202          return new org.hl7.fhir.dstu2.formats.JsonParser().composeBytes(VersionConvertorFactory_10_30.convertResource(VersionConvertorFactory_14_30.convertResource(res)));
203        } else if (VersionUtilities.isR2BVer(version)) {
204          return new org.hl7.fhir.dstu2016may.formats.JsonParser().composeBytes(res);
205        } else if (VersionUtilities.isR3Ver(version)) {
206          return new org.hl7.fhir.dstu3.formats.JsonParser().composeBytes(VersionConvertorFactory_14_30.convertResource(res));
207        } else if (VersionUtilities.isR4Ver(version)) {
208          return new org.hl7.fhir.r4.formats.JsonParser().composeBytes(VersionConvertorFactory_14_40.convertResource(res));
209        } else if (VersionUtilities.isR5Ver(version)) {
210          return new org.hl7.fhir.r5.formats.JsonParser().composeBytes(VersionConvertorFactory_14_50.convertResource(res));
211        }
212      } else if (VersionUtilities.isR3Ver(currentVersion)) {
213        org.hl7.fhir.dstu3.model.Resource res = new org.hl7.fhir.dstu3.formats.JsonParser().parse(cnt);
214        if (VersionUtilities.isR2Ver(version)) {
215          return new org.hl7.fhir.dstu2.formats.JsonParser().composeBytes(VersionConvertorFactory_10_30.convertResource(res));
216        } else if (VersionUtilities.isR2BVer(version)) {
217          return new org.hl7.fhir.dstu2016may.formats.JsonParser().composeBytes(VersionConvertorFactory_14_30.convertResource(res));
218        } else if (VersionUtilities.isR3Ver(version)) {
219          return new org.hl7.fhir.dstu3.formats.JsonParser().composeBytes(res);
220        } else if (VersionUtilities.isR4Ver(version)) {
221          return new org.hl7.fhir.r4.formats.JsonParser().composeBytes(VersionConvertorFactory_30_40.convertResource(res));
222        } else if (VersionUtilities.isR5Ver(version)) {
223          return new org.hl7.fhir.r5.formats.JsonParser().composeBytes(VersionConvertorFactory_30_50.convertResource(res));
224        }
225      } else if (VersionUtilities.isR4Ver(currentVersion)) {
226        org.hl7.fhir.r4.model.Resource res = new org.hl7.fhir.r4.formats.JsonParser().parse(cnt);
227        if (VersionUtilities.isR2Ver(version)) {
228          return new org.hl7.fhir.dstu2.formats.JsonParser().composeBytes(VersionConvertorFactory_10_40.convertResource(res, new PR2Handler()));
229        } else if (VersionUtilities.isR2BVer(version)) {
230          return new org.hl7.fhir.dstu2016may.formats.JsonParser().composeBytes(VersionConvertorFactory_14_40.convertResource(res));
231        } else if (VersionUtilities.isR3Ver(version)) {
232          return new org.hl7.fhir.dstu3.formats.JsonParser().composeBytes(VersionConvertorFactory_30_40.convertResource(res, new BaseAdvisor_30_40(false)));
233        } else if (VersionUtilities.isR4Ver(version)) {
234          return new org.hl7.fhir.r4.formats.JsonParser().composeBytes(res);
235        } else if (VersionUtilities.isR5Ver(version)) {
236          return new org.hl7.fhir.r5.formats.JsonParser().composeBytes(VersionConvertorFactory_40_50.convertResource(res));
237        }
238      } else if (VersionUtilities.isR5Ver(currentVersion)) {
239        org.hl7.fhir.r5.model.Resource res = new org.hl7.fhir.r5.formats.JsonParser().parse(cnt);
240        if (VersionUtilities.isR2Ver(version)) {
241          return new org.hl7.fhir.dstu2.formats.JsonParser().composeBytes(VersionConvertorFactory_10_50.convertResource(res));
242        } else if (VersionUtilities.isR2BVer(version)) {
243          return new org.hl7.fhir.dstu2016may.formats.JsonParser().composeBytes(VersionConvertorFactory_14_50.convertResource(res));
244        } else if (VersionUtilities.isR3Ver(version)) {
245          return new org.hl7.fhir.dstu3.formats.JsonParser().composeBytes(VersionConvertorFactory_30_50.convertResource(res, new BaseAdvisor_30_50(false)));
246        } else if (VersionUtilities.isR4Ver(version)) {
247          return new org.hl7.fhir.r4.formats.JsonParser().composeBytes(VersionConvertorFactory_40_50.convertResource(res));
248        } else if (VersionUtilities.isR5Ver(version)) {
249          return new org.hl7.fhir.r5.formats.JsonParser().composeBytes(res);
250        }
251      }
252      throw new Error("Unknown version " + currentVersion + " -> " + version);
253    } catch (Exception ex) {
254      ex.printStackTrace();
255      errors.add("Error converting " + n + ": " + ex.getMessage());
256      return null;
257    }
258  }
259
260}