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}