
001package org.hl7.fhir.r5.test.utils; 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.BufferedInputStream; 035import java.io.ByteArrayInputStream; 036import java.io.ByteArrayOutputStream; 037import java.io.File; 038import java.io.FileInputStream; 039import java.io.FileOutputStream; 040import java.io.IOException; 041import java.io.InputStream; 042import java.net.URL; 043import java.util.Collection; 044import java.util.HashMap; 045import java.util.List; 046import java.util.Map; 047import java.util.zip.ZipEntry; 048import java.util.zip.ZipInputStream; 049 050import org.apache.commons.io.FileUtils; 051import org.apache.commons.io.IOUtils; 052import org.apache.commons.lang3.NotImplementedException; 053import org.hl7.fhir.exceptions.FHIRException; 054import org.hl7.fhir.exceptions.FHIRFormatError; 055import org.hl7.fhir.r5.formats.IParser.OutputStyle; 056import org.hl7.fhir.r5.formats.JsonParser; 057import org.hl7.fhir.r5.formats.RdfParser; 058import org.hl7.fhir.r5.formats.RdfParserBase; 059import org.hl7.fhir.r5.formats.XmlParser; 060import org.hl7.fhir.r5.model.Constants; 061import org.hl7.fhir.r5.model.Resource; 062import org.hl7.fhir.utilities.FileUtilities; 063import org.hl7.fhir.utilities.Utilities; 064import org.hl7.fhir.utilities.filesystem.CSFile; 065import org.hl7.fhir.utilities.filesystem.CSFileInputStream; 066import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; 067import org.xmlpull.v1.XmlPullParser; 068import org.xmlpull.v1.XmlPullParserException; 069import org.xmlpull.v1.XmlPullParserFactory; 070 071@Deprecated 072@SuppressWarnings("checkstyle:systemout") 073public class ToolsHelper { 074 075 public static void main(String[] args) { 076 try { 077 ToolsHelper self = new ToolsHelper(); 078 if (args.length == 0) 079 throw new FHIRException("Missing Command Parameter. Valid Commands: round, json, version, fragments, snapshot-maker"); 080 if (args[0].equals("round")) 081 self.executeRoundTrip(args); 082 else if (args[0].equals("test")) 083 self.executeTest(args); 084 else if (args[0].equals("examples")) 085 self.executeExamples(args); 086 else if (args[0].equals("json")) 087 self.executeJson(args); 088 else if (args[0].equals("cxml")) 089 self.executeCanonicalXml(args); 090 else if (args[0].equals("version")) 091 self.executeVersion(args); 092 else if (args[0].equals("fragments")) 093 self.executeFragments(args); 094 else if (args[0].equals("snapshot-maker")) 095 self.generateSnapshots(args); 096 else 097 throw new FHIRException("Unknown command '"+args[0]+"'. Valid Commands: round, test, examples, json, cxml, version, fragments, snapshot-maker"); 098 } catch (Throwable e) { 099 try { 100 e.printStackTrace(); 101 FileUtilities.stringToFile(e.toString(), (args.length == 0 ? "tools" : args[0])+".err"); 102 } catch (Exception e1) { 103 e1.printStackTrace(); 104 } 105 } 106 } 107 108 private void executeExamples(String[] args) throws IOException { 109 try { 110 @SuppressWarnings("unchecked") 111 List<String> lines = FileUtils.readLines(ManagedFileAccess.file(args[1]), "UTF-8"); 112 String srcDir = lines.get(0); 113 lines.remove(0); 114 processExamples(srcDir, lines); 115 FileUtilities.stringToFile("ok", FileUtilities.changeFileExt(args[1], ".out")); 116 } catch (Exception e) { 117 FileUtilities.stringToFile(e.getMessage(), FileUtilities.changeFileExt(args[1], ".out")); 118 } 119 } 120 121 private void generateSnapshots(String[] args) throws IOException, FHIRException { 122 if (args.length == 1) { 123 System.out.println("tools.jar snapshot-maker [source] -defn [definitions]"); 124 System.out.println(""); 125 System.out.println("Generates a snapshot from a differential. The nominated profile must have a single struture that has a differential"); 126 System.out.println(""); 127 System.out.println("source - the profile to generate the snapshot for. Maybe a file name, or a URL reference to a server running FHIR RESTful API"); 128 System.out.println("definitions - filename for local copy of the validation.zip file"); 129 } 130 String address = args[1]; 131 String definitions = args[3]; 132 133// SimpleWorkerContext context = SimpleWorkerContext.fromDefinitions(getDefinitions(definitions)); 134 135 // if (address.startsWith("http:") || address.startsWith("http:")) { 136 // // this is on a restful interface 137 // String[] parts = address.split("\\/Profile\\/"); 138 // if (parts.length != 2) 139 // throw new FHIRException("Unable to understand address of profile"); 140 // StructureDefinition profile = context.fetchResource(StructureDefinition.class, parts[1]); 141 // ProfileUtilities utils = new ProfileUtilities(context); 142 // StructureDefinition base = utils.getProfile(profile, profile.getBase()); 143 // if (base == null) 144 // throw new FHIRException("Unable to resolve profile "+profile.getBase()); 145 // utils.generateSnapshot(base, profile, address, profile.getName(), null, null); 146 // // client.update(StructureDefinition.class, profile, parts[1]); 147 // } else { 148 throw new NotImplementedException("generating snapshots not done yet (address = "+address+")"); 149 // } 150 } 151 152 protected XmlPullParser loadXml(InputStream stream) throws XmlPullParserException, IOException { 153 BufferedInputStream input = new BufferedInputStream(stream); 154 XmlPullParserFactory factory = XmlPullParserFactory.newInstance(System.getProperty(XmlPullParserFactory.PROPERTY_NAME), null); 155 factory.setNamespaceAware(true); 156 XmlPullParser xpp = factory.newPullParser(); 157 xpp.setInput(input, "UTF-8"); 158 xpp.next(); 159 return xpp; 160 } 161 162 protected int nextNoWhitespace(XmlPullParser xpp) throws XmlPullParserException, IOException { 163 int eventType = xpp.getEventType(); 164 while (eventType == XmlPullParser.TEXT && xpp.isWhitespace()) 165 eventType = xpp.next(); 166 return eventType; 167 } 168 169 public void executeFragments(String[] args) throws IOException { 170 try { 171 File source = ManagedFileAccess.csfile(args[1]); 172 if (!source.exists()) 173 throw new FHIRException("Source File \""+source.getAbsolutePath()+"\" not found"); 174 XmlPullParser xpp = loadXml(ManagedFileAccess.inStream(source)); 175 nextNoWhitespace(xpp); 176 if (!xpp.getName().equals("tests")) 177 throw new FHIRFormatError("Unable to parse file - starts with "+xpp.getName()); 178 xpp.next(); 179 nextNoWhitespace(xpp); 180 StringBuilder s = new StringBuilder(); 181 s.append("<results>\r\n"); 182 int fail = 0; 183 while (xpp.getEventType() == XmlPullParser.START_TAG && xpp.getName().equals("test")) { 184 String id = xpp.getAttributeValue(null, "id"); 185 String type = xpp.getAttributeValue(null, "type"); 186 // test 187 xpp.next(); 188 nextNoWhitespace(xpp); 189 // pre 190 xpp.next(); 191 nextNoWhitespace(xpp); 192 XmlParser p = new XmlParser(); 193 try { 194 p.parseFragment(xpp, type); 195 s.append("<result id=\""+id+"\" outcome=\"ok\"/>\r\n"); 196 nextNoWhitespace(xpp); 197 } catch (Exception e) { 198 s.append("<result id=\""+id+"\" outcome=\"error\" msg=\""+Utilities.escapeXml(e.getMessage())+"\"/>\r\n"); 199 fail++; 200 } 201 while (xpp.getEventType() != XmlPullParser.END_TAG || !xpp.getName().equals("pre")) 202 xpp.next(); 203 xpp.next(); 204 nextNoWhitespace(xpp); 205 xpp.next(); 206 nextNoWhitespace(xpp); 207 } 208 s.append("</results>\r\n"); 209 210 FileUtilities.stringToFile(s.toString(), args[2]); 211 } catch (Exception e) { 212 e.printStackTrace(); 213 FileUtilities.stringToFile(e.getMessage(), args[2]); 214 } 215 } 216 217 public void executeRoundTrip(String[] args) throws IOException, FHIRException { 218 FileInputStream in; 219 File source = ManagedFileAccess.csfile(args[1]); 220 File dest = ManagedFileAccess.csfile(args[2]); 221 if (args.length >= 4) { 222 FileUtilities.copyFile(args[1], args[3]); 223 } 224 225 if (!source.exists()) 226 throw new FHIRException("Source File \""+source.getAbsolutePath()+"\" not found"); 227 in = new CSFileInputStream(source); 228 XmlParser p = new XmlParser(); 229 JsonParser parser = new JsonParser(); 230 JsonParser pj = parser; 231 Resource rf = p.parse(in); 232 ByteArrayOutputStream json = new ByteArrayOutputStream(); 233 parser.setOutputStyle(OutputStyle.PRETTY); 234 parser.compose(json, rf); 235 json.close(); 236 FileUtilities.stringToFile(new String(json.toByteArray()), FileUtilities.changeFileExt(dest.getAbsolutePath(), ".json")); 237 rf = pj.parse(new ByteArrayInputStream(json.toByteArray())); 238 FileOutputStream s = ManagedFileAccess.outStream(dest); 239 new XmlParser().compose(s, rf, true); 240 s.close(); 241 } 242 243 public String executeJson(String[] args) throws IOException, FHIRException { 244 FileInputStream in; 245 File source = ManagedFileAccess.csfile(args[1]); 246 File dest = ManagedFileAccess.csfile(args[2]); 247 File destc = ManagedFileAccess.csfile(FileUtilities.changeFileExt(args[2], ".canonical.json")); 248 File destt = ManagedFileAccess.csfile(args[2]+".tmp"); 249 File destr = ManagedFileAccess.csfile(FileUtilities.changeFileExt(args[2], ".ttl")); 250 251 if (!source.exists()) 252 throw new FHIRException("Source File \""+source.getAbsolutePath()+"\" not found"); 253 in = new CSFileInputStream(source); 254 XmlParser p = new XmlParser(); 255 Resource rf = p.parse(in); 256 JsonParser json = new JsonParser(); 257 json.setOutputStyle(OutputStyle.PRETTY); 258 FileOutputStream s = ManagedFileAccess.outStream(dest); 259 json.compose(s, rf); 260 s.close(); 261 json.setOutputStyle(OutputStyle.CANONICAL); 262 s = ManagedFileAccess.outStream(destc); 263 json.compose(s, rf); 264 s.close(); 265 json.setSuppressXhtml("Snipped for Brevity"); 266 json.setOutputStyle(OutputStyle.PRETTY); 267 s = ManagedFileAccess.outStream(destt); 268 json.compose(s, rf); 269 s.close(); 270 271 RdfParserBase rdf = new RdfParser(); 272 s = ManagedFileAccess.outStream(destr); 273 rdf.compose(s, rf); 274 s.close(); 275 276 return FileUtilities.fileToString(destt.getAbsolutePath()); 277 } 278 279 public void executeCanonicalXml(String[] args) throws FHIRException, IOException { 280 FileInputStream in; 281 File source = ManagedFileAccess.csfile(args[1]); 282 File dest = ManagedFileAccess.csfile(args[2]); 283 284 if (!source.exists()) 285 throw new FHIRException("Source File \""+source.getAbsolutePath()+"\" not found"); 286 in = new CSFileInputStream(source); 287 XmlParser p = new XmlParser(); 288 Resource rf = p.parse(in); 289 XmlParser cxml = new XmlParser(); 290 cxml.setOutputStyle(OutputStyle.NORMAL); 291 cxml.compose(ManagedFileAccess.outStream(dest), rf); 292 } 293 294 private void executeVersion(String[] args) throws IOException { 295 FileUtilities.stringToFile(org.hl7.fhir.r5.utils.Version.VERSION+":"+Constants.VERSION, args[1]); 296 } 297 298 public void processExamples(String rootDir, Collection<String> list) throws FHIRException { 299 for (String n : list) { 300 try { 301 String filename = rootDir + n + ".xml"; 302 // 1. produce canonical XML 303 CSFileInputStream source = new CSFileInputStream(filename); 304 FileOutputStream dest = ManagedFileAccess.outStream(FileUtilities.changeFileExt(filename, ".canonical.xml")); 305 XmlParser p = new XmlParser(); 306 Resource r = p.parse(source); 307 XmlParser cxml = new XmlParser(); 308 cxml.setOutputStyle(OutputStyle.CANONICAL); 309 cxml.compose(dest, r); 310 311 // 2. produce JSON 312 source = new CSFileInputStream(filename); 313 dest = ManagedFileAccess.outStream(FileUtilities.changeFileExt(filename, ".json")); 314 r = p.parse(source); 315 JsonParser json = new JsonParser(); 316 json.setOutputStyle(OutputStyle.PRETTY); 317 json.compose(dest, r); 318 json = new JsonParser(); 319 json.setOutputStyle(OutputStyle.CANONICAL); 320 dest = ManagedFileAccess.outStream(FileUtilities.changeFileExt(filename, ".canonical.json")); 321 json.compose(dest, r); 322 323 // 2. produce JSON 324 dest = ManagedFileAccess.outStream(FileUtilities.changeFileExt(filename, ".ttl")); 325 RdfParserBase rdf = new RdfParser(); 326 rdf.compose(dest, r); 327 } catch (Exception e) { 328 e.printStackTrace(); 329 throw new FHIRException("Error Processing "+n+".xml: "+e.getMessage(), e); 330 } 331 } 332 } 333 334 public void testRoundTrip(String rootDir, String tmpDir, Collection<String> names) throws Throwable { 335 try { 336 System.err.println("Round trip from "+rootDir+" to "+tmpDir+":"+Integer.toString(names.size())+" files"); 337 for (String n : names) { 338 System.err.print(" "+n); 339 String source = rootDir + n + ".xml"; 340 // String tmpJson = tmpDir + n + ".json"; 341 String tmp = tmpDir + n.replace(File.separator, "-") + ".tmp"; 342 String dest = tmpDir + n.replace(File.separator, "-") + ".java.xml"; 343 344 FileInputStream in = ManagedFileAccess.inStream(source); 345 XmlParser xp = new XmlParser(); 346 Resource r = xp.parse(in); 347 System.err.print("."); 348 JsonParser jp = new JsonParser(); 349 FileOutputStream out = ManagedFileAccess.outStream(tmp); 350 jp.setOutputStyle(OutputStyle.PRETTY); 351 jp.compose(out, r); 352 out.close(); 353 r = null; 354 System.err.print("."); 355 356 in = ManagedFileAccess.inStream(tmp); 357 System.err.print(","); 358 r = jp.parse(in); 359 System.err.print("."); 360 out = ManagedFileAccess.outStream(dest); 361 new XmlParser().compose(out, r, true); 362 System.err.println("!"); 363 out.close(); 364 r = null; 365 System.gc(); 366 } 367 } catch (Throwable e) { 368 System.err.println("Error: "+e.getMessage()); 369 throw e; 370 } 371 } 372 373 private void executeTest(String[] args) throws Throwable { 374 try { 375 @SuppressWarnings("unchecked") 376 List<String> lines = FileUtils.readLines(ManagedFileAccess.file(args[1]), "UTF-8"); 377 String srcDir = lines.get(0); 378 lines.remove(0); 379 String dstDir = lines.get(0).trim(); 380 lines.remove(0); 381 testRoundTrip(srcDir, dstDir, lines); 382 FileUtilities.stringToFile("ok", FileUtilities.changeFileExt(args[1], ".out")); 383 } catch (Exception e) { 384 FileUtilities.stringToFile(e.getMessage(), FileUtilities.changeFileExt(args[1], ".out")); 385 } 386 } 387 388 389}