001package org.hl7.fhir.utilities;
002
003/*
004  Copyright (c) 2011+, HL7, Inc.
005  All rights reserved.
006  
007  Redistribution and use in source and binary forms, with or without modification, 
008  are permitted provided that the following conditions are met:
009    
010   * Redistributions of source code must retain the above copyright notice, this 
011     list of conditions and the following disclaimer.
012   * Redistributions in binary form must reproduce the above copyright notice, 
013     this list of conditions and the following disclaimer in the documentation 
014     and/or other materials provided with the distribution.
015   * Neither the name of HL7 nor the names of its contributors may be used to 
016     endorse or promote products derived from this software without specific 
017     prior written permission.
018  
019  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
020  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
021  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
022  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
023  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
024  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
025  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
026  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
027  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
028  POSSIBILITY OF SUCH DAMAGE.
029  
030 */
031
032
033
034import java.io.File;
035import java.io.FileInputStream;
036import java.io.FileNotFoundException;
037import java.io.FileOutputStream;
038import java.io.IOException;
039import java.io.OutputStreamWriter;
040import java.util.ArrayList;
041import java.util.Collections;
042import java.util.HashMap;
043import java.util.HashSet;
044import java.util.List;
045import java.util.Map;
046import java.util.Set;
047
048import com.google.gson.Gson;
049import com.google.gson.GsonBuilder;
050import com.google.gson.JsonElement;
051import com.google.gson.JsonObject;
052import com.google.gson.JsonSyntaxException;
053
054public class NDJsonWriter {
055
056  private class ResourceInfo {
057    private FileOutputStream stream;
058    private Set<String> ids = new HashSet<String>();
059    public OutputStreamWriter writer;
060  }
061  
062  private static com.google.gson.JsonParser  parser = new com.google.gson.JsonParser();
063  private Gson gson = new GsonBuilder().create();
064  private Map<String, ResourceInfo> outputs = new HashMap<String, ResourceInfo>();
065  private String filename;
066  private String scratch;
067  
068  public NDJsonWriter(String filename, String scratch) {
069    this.filename = filename;
070    this.scratch = scratch;
071    outputs.clear();
072  }
073
074  public void addFilesFiltered(String actualDir, String ext, String[] noExt) throws IOException {
075    File f = new CSFile(actualDir);
076
077    String files[] = f.list();
078    for (int i = 0; i < files.length; i++) {
079      if ( new CSFile(actualDir + files[i]).isFile() && ((ext == null || files[i].endsWith(ext)))) {
080        boolean ok = true;
081        for (String n : noExt) {
082          ok = ok && !files[i].endsWith(n);
083        }
084        if (ok) {
085          addFile(Utilities.path(actualDir, files[i]));
086        }
087      }
088    }
089  }
090
091  private void addFile(String path) throws JsonSyntaxException, FileNotFoundException, IOException {
092    JsonObject js = parser.parse(TextFile.fileToString(path)).getAsJsonObject();
093    if (js.has("resourceType")) {
094      addResource(js);  
095    }
096  }
097
098  private void addResource(JsonObject js) throws IOException {
099    String rn = js.get("resourceType").getAsString();    
100    if (rn.equals("Bundle")) {
101      if (js.has("entry")) {
102        for (JsonElement item : js.getAsJsonArray("entry")) {
103          if (item instanceof JsonObject && ((JsonObject) item).has("resource")) {
104            JsonObject r = (JsonObject) ((JsonObject) item).get("resource");
105            rn = r.get("resourceType").getAsString();
106            addResource(r);  
107          }
108        }
109      }
110    } else {
111      if (!js.has("id"))
112        return;
113
114      String id = js.get("id").getAsString();
115      String json = gson.toJson(js);
116      
117      if (outputs.containsKey(rn)) { 
118        ResourceInfo ri = outputs.get(rn);
119        if (!ri.ids.contains(id)) {
120          ri.ids.add(id);
121          ri.writer.append("\r\n");      
122          ri.writer.append(json);
123        }
124      } else {
125        ResourceInfo ri = new ResourceInfo();
126        outputs.put(rn, ri);
127        ri.ids.add(id);
128        ri.stream = new FileOutputStream(Utilities.path(scratch, rn+".ndjson"));
129        ri.writer = new OutputStreamWriter(ri.stream, "UTF-8");
130        ri.writer.append(json);      
131      }
132    }
133  }
134
135  public void close() throws IOException {
136    ZipGenerator zip = new ZipGenerator(filename);
137    for (String rn : sorted(outputs.keySet())) {
138      ResourceInfo ri = outputs.get(rn);
139      ri.writer.flush();
140      ri.writer.close();
141      ri.stream.close();
142      
143      zip.addStream(rn+".ndjson", new FileInputStream(Utilities.path(scratch, rn+".ndjson")), false);
144    }
145    zip.close();
146  }
147
148  private List<String> sorted(Set<String> keys) {
149    List<String> res = new ArrayList<String>();
150    res.addAll(keys);
151    Collections.sort(res);
152    return res;
153  }
154
155  public static void main(String[] args) throws IOException {
156    String dstDir = "C:\\work\\org.hl7.fhir\\build\\publish\\";
157    NDJsonWriter ndjson = new NDJsonWriter(dstDir + "examples-ndjson.zip", Utilities.path("[tmp]", "ndjson"));
158    ndjson.addFilesFiltered(dstDir, ".json", new String[] {".schema.json", ".canonical.json", ".diff.json", "expansions.json", "package.json"});
159    ndjson.close();
160  }
161
162}