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}