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