001package org.hl7.fhir.validation.cli.utils;
002
003import java.io.File;
004import java.util.Arrays;
005import java.util.Locale;
006
007import org.hl7.fhir.exceptions.FHIRException;
008import org.hl7.fhir.r5.terminologies.JurisdictionUtilities;
009import org.hl7.fhir.r5.utils.validation.BundleValidationRule;
010import org.hl7.fhir.utilities.VersionUtilities;
011import org.hl7.fhir.validation.cli.model.CliContext;
012import org.hl7.fhir.validation.cli.model.HtmlInMarkdownCheck;
013
014public class Params {
015
016  public static final String VERSION = "-version";
017  public static final String OUTPUT = "-output";
018
019  public static final String OUTPUT_SUFFIX = "-outputSuffix";
020  public static final String LEVEL = "-level";
021  public static final String HTML_OUTPUT = "-html-output";
022  public static final String PROXY = "-proxy";
023
024  public static final String HTTPS_PROXY = "-https-proxy";
025  public static final String PROXY_AUTH = "-auth";
026  public static final String PROFILE = "-profile";
027  public static final String BUNDLE = "-bundle";
028  public static final String QUESTIONNAIRE = "-questionnaire";
029  public static final String NATIVE = "-native";
030  public static final String ASSUME_VALID_REST_REF = "-assumeValidRestReferences";
031  public static final String DEBUG = "-debug";
032  public static final String SCT = "-sct";
033  public static final String RECURSE = "-recurse";
034  public static final String SHOW_MESSAGES_FROM_REFERENCES = "-showReferenceMessages";
035  public static final String LOCALE = "-locale";
036  public static final String EXTENSION = "-extension";
037  public static final String HINT_ABOUT_NON_MUST_SUPPORT = "-hintAboutNonMustSupport";
038  public static final String TO_VERSION = "-to-version";
039  public static final String DO_NATIVE = "-do-native";
040  public static final String NO_NATIVE = "-no-native";
041  public static final String COMPILE = "-compile";
042  public static final String TRANSFORM = "-transform";
043  public static final String NARRATIVE = "-narrative";
044  public static final String SNAPSHOT = "-snapshot";
045  public static final String SCAN = "-scan";
046  public static final String TERMINOLOGY = "-tx";
047  public static final String TERMINOLOGY_LOG = "-txLog";
048  public static final String TERMINOLOGY_CACHE = "-txCache";
049  public static final String LOG = "-log";
050  public static final String LANGUAGE = "-language";
051  public static final String IMPLEMENTATION_GUIDE = "-ig";
052  public static final String DEFINITION = "defn";
053  public static final String MAP = "-map";
054  public static final String X = "-x";
055  public static final String CONVERT = "-convert";
056  public static final String FHIRPATH = "-fhirpath";
057  public static final String TEST = "-tests";
058  public static final String HELP = "help";
059  public static final String COMPARE = "-compare";
060  public static final String SPREADSHEET = "-spreadsheet";
061  public static final String DESTINATION = "-dest";
062  public static final String LEFT = "-left";
063  public static final String RIGHT = "-right";
064  public static final String NO_INTERNAL_CACHING = "-no-internal-caching";
065  public static final String NO_EXTENSIBLE_BINDING_WARNINGS = "-no-extensible-binding-warnings";
066  public static final String NO_UNICODE_BIDI_CONTROL_CHARS = "-no_unicode_bidi_control_chars";
067  public static final String NO_INVARIANTS = "-no-invariants";
068  public static final String WANT_INVARIANTS_IN_MESSAGES = "-want-invariants-in-messages";
069  public static final String SECURITY_CHECKS = "-security-checks";
070  public static final String CRUMB_TRAIL = "-crumb-trails";
071  public static final String FOR_PUBLICATION = "-forPublication";
072  public static final String VERBOSE = "-verbose";
073  public static final String SHOW_TIMES = "-show-times";
074  public static final String ALLOW_EXAMPLE_URLS = "-allow-example-urls";
075  public static final String OUTPUT_STYLE = "-output-style";
076  public static final String DO_IMPLICIT_FHIRPATH_STRING_CONVERSION = "-implicit-fhirpath-string-conversions";
077  public static final String JURISDICTION = "-jurisdiction";
078  public static final String HTML_IN_MARKDOWN = "-html-in-markdown";
079
080  public static final String RUN_TESTS = "-run-tests";
081
082  public static final String TEST_MODULES = "-test-modules";
083
084  public static final String TEST_NAME_FILTER = "-test-classname-filter";
085
086  /**
087   * Checks the list of passed in params to see if it contains the passed in param.
088   *
089   * @param args  Array of params to search.
090   * @param param {@link String} param to search for.
091   * @return {@link Boolean#TRUE} if the list contains the given param.
092   */
093  public static boolean hasParam(String[] args, String param) {
094    return Arrays.asList(args).contains(param);
095  }
096
097  /**
098   * Fetches the  value for the passed in param from the provided list of params.
099   *
100   * @param args  Array of params to search.
101   * @param param {@link String} param keyword to search for.
102   * @return {@link String} value for the provided param.
103   */
104  public static String getParam(String[] args, String param) {
105    for (int i = 0; i < args.length - 1; i++) {
106      if (args[i].equals(param)) return args[i + 1];
107    }
108    return null;
109  }
110
111  /**
112   * TODO Don't do this all in one for loop. Use the above methods.
113   */
114  public static CliContext loadCliContext(String[] args) throws Exception {
115    CliContext cliContext = new CliContext();
116
117    // load the parameters - so order doesn't matter
118    for (int i = 0; i < args.length; i++) {
119      if (args[i].equals(VERSION)) {
120        cliContext.setSv(VersionUtilities.getCurrentPackageVersion(args[++i]));
121      } else if (args[i].equals(OUTPUT)) {
122        if (i + 1 == args.length)
123          throw new Error("Specified -output without indicating output file");
124        else
125          cliContext.setOutput(args[++i]);
126      } else if (args[i].equals(OUTPUT_SUFFIX)) {
127        if (i + 1 == args.length)
128          throw new Error("Specified -outputSuffix without indicating output suffix");
129        else
130          cliContext.setOutputSuffix(args[++i]);
131      }
132      else if (args[i].equals(HTML_OUTPUT)) {
133        if (i + 1 == args.length)
134          throw new Error("Specified -html-output without indicating output file");
135        else
136          cliContext.setHtmlOutput(args[++i]);
137      } else if (args[i].equals(PROXY)) {
138        i++; // ignore next parameter
139      } else if (args[i].equals(PROXY_AUTH)) {
140        i++;
141      } else if (args[i].equals(HTTPS_PROXY)) {
142        i++;
143      }
144      else if (args[i].equals(PROFILE)) {
145        String p = null;
146        if (i + 1 == args.length) {
147          throw new Error("Specified -profile without indicating profile source");
148        } else {
149          p = args[++i];
150          cliContext.addProfile(p);
151        }
152      } else if (args[i].equals(BUNDLE)) {
153        String p = null;
154        String r = null;
155        if (i + 1 == args.length) {
156          throw new Error("Specified -profile without indicating bundle rule ");
157        } else {
158          r = args[++i];
159        }
160        if (i + 1 == args.length) {
161          throw new Error("Specified -profile without indicating profile source");
162        } else {
163          p = args[++i];
164        }
165        cliContext.getBundleValidationRules().add(new BundleValidationRule(r, p));
166      } else if (args[i].equals(QUESTIONNAIRE)) {
167        if (i + 1 == args.length)
168          throw new Error("Specified -questionnaire without indicating questionnaire mode");
169        else {
170          String q = args[++i];
171          cliContext.setQuestionnaireMode(QuestionnaireMode.fromCode(q));
172        }
173      } else if (args[i].equals(LEVEL)) {
174        if (i + 1 == args.length)
175          throw new Error("Specified -level without indicating level mode");
176        else {
177          String q = args[++i];
178          cliContext.setLevel(ValidationLevel.fromCode(q));
179        }
180      } else if (args[i].equals(NATIVE)) {
181        cliContext.setDoNative(true);
182      } else if (args[i].equals(ASSUME_VALID_REST_REF)) {
183        cliContext.setAssumeValidRestReferences(true);
184      } else if (args[i].equals(DEBUG)) {
185        cliContext.setDoDebug(true);
186      } else if (args[i].equals(SCT)) {
187        cliContext.setSnomedCT(args[++i]);
188      } else if (args[i].equals(RECURSE)) {
189        cliContext.setRecursive(true);
190      } else if (args[i].equals(SHOW_MESSAGES_FROM_REFERENCES)) {
191        cliContext.setShowMessagesFromReferences(true);
192      } else if (args[i].equals(DO_IMPLICIT_FHIRPATH_STRING_CONVERSION)) {
193        cliContext.setDoImplicitFHIRPathStringConversion(true);
194      } else if (args[i].equals(HTML_IN_MARKDOWN)) {
195        if (i + 1 == args.length)
196          throw new Error("Specified "+HTML_IN_MARKDOWN+" without indicating mode");
197        else {
198          String q = args[++i];
199          if (!HtmlInMarkdownCheck.isValidCode(q)) {
200            throw new Error("Specified "+HTML_IN_MARKDOWN+" with na invalid code - must be ignore, warning, or error");            
201          } else {
202            cliContext.setHtmlInMarkdownCheck(HtmlInMarkdownCheck.fromCode(q));
203          }
204        }
205      } else if (args[i].equals(LOCALE)) {
206        if (i + 1 == args.length) {
207          throw new Error("Specified -locale without indicating locale");
208        } else {
209          cliContext.setLocale(new Locale(args[++i]));
210        }
211      } else if (args[i].equals(EXTENSION)) {
212        cliContext.getExtensions().add(args[++i]);
213      } else if (args[i].equals(NO_INTERNAL_CACHING)) {
214        cliContext.setNoInternalCaching(true);
215      } else if (args[i].equals(NO_EXTENSIBLE_BINDING_WARNINGS)) {
216        cliContext.setNoExtensibleBindingMessages(true);
217      } else if (args[i].equals(NO_UNICODE_BIDI_CONTROL_CHARS)) {
218        cliContext.setNoUnicodeBiDiControlChars(true);
219      } else if (args[i].equals(NO_INVARIANTS)) {
220        cliContext.setNoInvariants(true);
221      } else if (args[i].equals(WANT_INVARIANTS_IN_MESSAGES)) {
222        cliContext.setWantInvariantsInMessages(true);
223      } else if (args[i].equals(HINT_ABOUT_NON_MUST_SUPPORT)) {
224        cliContext.setHintAboutNonMustSupport(true);
225      } else if (args[i].equals(TO_VERSION)) {
226        cliContext.setTargetVer(args[++i]);
227        cliContext.setMode(EngineMode.VERSION);
228      } else if (args[i].equals(DO_NATIVE)) {
229        cliContext.setCanDoNative(true);
230      } else if (args[i].equals(NO_NATIVE)) {
231        cliContext.setCanDoNative(false);
232      } else if (args[i].equals(TRANSFORM)) {
233        cliContext.setMap(args[++i]);
234        cliContext.setMode(EngineMode.TRANSFORM);
235      } else if (args[i].equals(COMPILE)) {
236        cliContext.setMap(args[++i]);
237        cliContext.setMode(EngineMode.COMPILE);
238      } else if (args[i].equals(NARRATIVE)) {
239        cliContext.setMode(EngineMode.NARRATIVE);
240      } else if (args[i].equals(SPREADSHEET)) {
241        cliContext.setMode(EngineMode.SPREADSHEET);
242      } else if (args[i].equals(SNAPSHOT)) {
243        cliContext.setMode(EngineMode.SNAPSHOT);
244      } else if (args[i].equals(RUN_TESTS)) {
245        // TODO setBaseTestingUtils test directory
246        cliContext.setMode(EngineMode.RUN_TESTS);
247      } else if (args[i].equals(SECURITY_CHECKS)) {
248        cliContext.setSecurityChecks(true);
249      } else if (args[i].equals(CRUMB_TRAIL)) {
250        cliContext.setCrumbTrails(true);
251      } else if (args[i].equals(FOR_PUBLICATION)) {
252        cliContext.setForPublication(true);
253      } else if (args[i].equals(VERBOSE)) {
254        cliContext.setCrumbTrails(true);
255      } else if (args[i].equals(ALLOW_EXAMPLE_URLS)) {
256        String bl = args[++i]; 
257        if ("true".equals(bl)) {
258          cliContext.setAllowExampleUrls(true);
259        } else if ("false".equals(bl)) {
260          cliContext.setAllowExampleUrls(false);
261        } else {
262          throw new Error("Value for "+ALLOW_EXAMPLE_URLS+" not understood: "+bl);          
263        }          
264      } else if (args[i].equals(SHOW_TIMES)) {
265        cliContext.setShowTimes(true);
266      } else if (args[i].equals(OUTPUT_STYLE)) {
267        cliContext.setOutputStyle(args[++i]);
268      } else if (args[i].equals(SCAN)) {
269        cliContext.setMode(EngineMode.SCAN);
270      } else if (args[i].equals(TERMINOLOGY)) {
271        if (i + 1 == args.length)
272          throw new Error("Specified -tx without indicating terminology server");
273        else
274          cliContext.setTxServer("n/a".equals(args[++i]) ? null : args[i]);
275      } else if (args[i].equals(TERMINOLOGY_LOG)) {
276        if (i + 1 == args.length)
277          throw new Error("Specified -txLog without indicating file");
278        else
279          cliContext.setTxLog(args[++i]);
280      } else if (args[i].equals(TERMINOLOGY_CACHE)) {
281        if (i + 1 == args.length)
282          throw new Error("Specified -txCache without indicating file");
283        else
284          cliContext.setTxCache(args[++i]);
285      }
286      else if (args[i].equals(LOG)) {
287        if (i + 1 == args.length)
288          throw new Error("Specified -log without indicating file");
289        else
290          cliContext.setMapLog(args[++i]);
291      } else if (args[i].equals(LANGUAGE)) {
292        if (i + 1 == args.length)
293          throw new Error("Specified -language without indicating language");
294        else
295          cliContext.setLang(args[++i]);
296      } else if (args[i].equals(JURISDICTION)) {
297        if (i + 1 == args.length)
298          throw new Error("Specified -jurisdiction without indicating jurisdiction");
299        else
300          cliContext.setJurisdiction(processJurisdiction(args[++i]));
301      } else if (args[i].equals(IMPLEMENTATION_GUIDE) || args[i].equals(DEFINITION)) {
302        if (i + 1 == args.length)
303          throw new Error("Specified " + args[i] + " without indicating ig file");
304        else {
305          String s = args[++i];
306          String version = Common.getVersionFromIGName(null, s);
307          if (version == null) {
308            cliContext.addIg(s);
309          } else {
310            cliContext.setSv(version);
311          }
312        }
313      } else if (args[i].equals(MAP)) {
314        if (cliContext.getMap() == null) {
315          if (i + 1 == args.length)
316            throw new Error("Specified -map without indicating map file");
317          else
318            cliContext.setMap(args[++i]);
319        } else {
320          throw new Exception("Can only nominate a single -map parameter");
321        }
322      } else if (args[i].startsWith(X)) {
323        i++;
324      } else if (args[i].equals(CONVERT)) {
325        cliContext.setMode(EngineMode.CONVERT);
326      } else if (args[i].equals(FHIRPATH)) {
327        cliContext.setMode(EngineMode.FHIRPATH);
328        if (cliContext.getFhirpath() == null)
329          if (i + 1 == args.length)
330            throw new Error("Specified -fhirpath without indicating a FHIRPath expression");
331          else
332            cliContext.setFhirpath(args[++i]);
333        else
334          throw new Exception("Can only nominate a single -fhirpath parameter");
335      } else {
336        cliContext.addSource(args[i]);
337      }
338    }
339    return cliContext;
340  }
341
342  private static String processJurisdiction(String s) {
343    if (s.startsWith("urn:iso:std:iso:3166#") || s.startsWith("urn:iso:std:iso:3166:-2#") || s.startsWith("http://unstats.un.org/unsd/methods/m49/m49.htm#")) {
344      return s;
345    } else {
346      String v = JurisdictionUtilities.getJurisdictionFromLocale(s);
347      if (v != null) { 
348        return v;        
349      } else {
350        throw new FHIRException("Unable to understand Jurisdiction '"+s+"'");
351      }
352    }
353  }
354
355  public static String getTerminologyServerLog(String[] args) {
356    String txLog = null;
357    if (hasParam(args, "-txLog")) {
358      txLog = getParam(args, "-txLog");
359      new File(txLog).delete();
360    }
361    return txLog;
362  }
363
364  public static void checkIGFileReferences(String[] args) {
365    for (int i = 0; i < args.length; i++) {
366      if (IMPLEMENTATION_GUIDE.equals(args[i])) {
367        if (i + 1 == args.length)
368          throw new Error("Specified -ig without indicating ig file");
369        else {
370          String s = args[++i];
371          if (!s.startsWith("hl7.fhir.core-")) {
372            System.out.println("Load Package: " + s);
373          }
374        }
375      }
376    }
377  }
378}