This commit is contained in:
Grahame Grieve 2020-10-24 06:07:03 +11:00
commit 02b49913b0
57 changed files with 1117 additions and 2144 deletions

View File

@ -39,6 +39,7 @@ import org.hl7.fhir.utilities.DateTimeUtil;
import java.text.ParseException; import java.text.ParseException;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static ca.uhn.fhir.model.api.TemporalPrecisionEnum.*; import static ca.uhn.fhir.model.api.TemporalPrecisionEnum.*;
@ -74,6 +75,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
private static final FastDateFormat ourHumanDateTimeFormat = FastDateFormat.getDateTimeInstance(FastDateFormat.MEDIUM, FastDateFormat.MEDIUM); private static final FastDateFormat ourHumanDateTimeFormat = FastDateFormat.getDateTimeInstance(FastDateFormat.MEDIUM, FastDateFormat.MEDIUM);
private static final FastDateFormat ourHumanDateFormat = FastDateFormat.getDateInstance(FastDateFormat.MEDIUM); private static final FastDateFormat ourHumanDateFormat = FastDateFormat.getDateInstance(FastDateFormat.MEDIUM);
private static final Map<String, TimeZone> timezoneCache = new ConcurrentHashMap<>();
static { static {
ArrayList<FastDateFormat> formatters = new ArrayList<FastDateFormat>(); ArrayList<FastDateFormat> formatters = new ArrayList<FastDateFormat>();
@ -159,7 +161,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
return ourYearFormat.format(theValue); return ourYearFormat.format(theValue);
case MINUTE: case MINUTE:
if (myTimeZoneZulu) { if (myTimeZoneZulu) {
GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT")); GregorianCalendar cal = new GregorianCalendar(getTimeZone("GMT"));
cal.setTime(theValue); cal.setTime(theValue);
return ourYearMonthDayTimeMinsFormat.format(cal) + "Z"; return ourYearMonthDayTimeMinsFormat.format(cal) + "Z";
} else if (myTimeZone != null) { } else if (myTimeZone != null) {
@ -171,7 +173,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
} }
case SECOND: case SECOND:
if (myTimeZoneZulu) { if (myTimeZoneZulu) {
GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT")); GregorianCalendar cal = new GregorianCalendar(getTimeZone("GMT"));
cal.setTime(theValue); cal.setTime(theValue);
return ourYearMonthDayTimeFormat.format(cal) + "Z"; return ourYearMonthDayTimeFormat.format(cal) + "Z";
} else if (myTimeZone != null) { } else if (myTimeZone != null) {
@ -183,7 +185,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
} }
case MILLI: case MILLI:
if (myTimeZoneZulu) { if (myTimeZoneZulu) {
GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT")); GregorianCalendar cal = new GregorianCalendar(getTimeZone("GMT"));
cal.setTime(theValue); cal.setTime(theValue);
return ourYearMonthDayTimeMilliFormat.format(cal) + "Z"; return ourYearMonthDayTimeMilliFormat.format(cal) + "Z";
} else if (myTimeZone != null) { } else if (myTimeZone != null) {
@ -410,9 +412,9 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
if (theValueString.endsWith("Z")) { if (theValueString.endsWith("Z")) {
setTimeZoneZulu(true); setTimeZoneZulu(true);
} else if (theValueString.indexOf("GMT", timeZoneStart) != -1) { } else if (theValueString.indexOf("GMT", timeZoneStart) != -1) {
setTimeZone(TimeZone.getTimeZone(theValueString.substring(timeZoneStart))); setTimeZone(getTimeZone(theValueString.substring(timeZoneStart)));
} else if (theValueString.indexOf('+', timeZoneStart) != -1 || theValueString.indexOf('-', timeZoneStart) != -1) { } else if (theValueString.indexOf('+', timeZoneStart) != -1 || theValueString.indexOf('-', timeZoneStart) != -1) {
setTimeZone(TimeZone.getTimeZone("GMT" + theValueString.substring(timeZoneStart))); setTimeZone(getTimeZone("GMT" + theValueString.substring(timeZoneStart)));
} }
} }
@ -528,9 +530,9 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
int hours = offsetAbs / 60; int hours = offsetAbs / 60;
if (theZoneOffsetMinutes < 0) { if (theZoneOffsetMinutes < 0) {
setTimeZone(TimeZone.getTimeZone("GMT-" + hours + ":" + mins)); setTimeZone(getTimeZone("GMT-" + hours + ":" + mins));
} else { } else {
setTimeZone(TimeZone.getTimeZone("GMT+" + hours + ":" + mins)); setTimeZone(getTimeZone("GMT+" + hours + ":" + mins));
} }
} }
@ -618,4 +620,8 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
} }
} }
private TimeZone getTimeZone(String offset) {
return timezoneCache.computeIfAbsent(offset, TimeZone::getTimeZone);
}
} }

View File

@ -35,7 +35,9 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.Map;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum; import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -52,6 +54,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
static final long NANOS_PER_MILLIS = 1000000L; static final long NANOS_PER_MILLIS = 1000000L;
static final long NANOS_PER_SECOND = 1000000000L; static final long NANOS_PER_SECOND = 1000000000L;
private static final Map<String, TimeZone> timezoneCache = new ConcurrentHashMap<>();
private static final FastDateFormat ourHumanDateFormat = FastDateFormat.getDateInstance(FastDateFormat.MEDIUM); private static final FastDateFormat ourHumanDateFormat = FastDateFormat.getDateInstance(FastDateFormat.MEDIUM);
private static final FastDateFormat ourHumanDateTimeFormat = FastDateFormat.getDateTimeInstance(FastDateFormat.MEDIUM, FastDateFormat.MEDIUM); private static final FastDateFormat ourHumanDateTimeFormat = FastDateFormat.getDateTimeInstance(FastDateFormat.MEDIUM, FastDateFormat.MEDIUM);
@ -114,7 +117,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
} else { } else {
GregorianCalendar cal; GregorianCalendar cal;
if (myTimeZoneZulu) { if (myTimeZoneZulu) {
cal = new GregorianCalendar(TimeZone.getTimeZone("GMT")); cal = new GregorianCalendar(getTimeZone("GMT"));
} else if (myTimeZone != null) { } else if (myTimeZone != null) {
cal = new GregorianCalendar(myTimeZone); cal = new GregorianCalendar(myTimeZone);
} else { } else {
@ -209,7 +212,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
*/ */
public TimeZone getTimeZone() { public TimeZone getTimeZone() {
if (myTimeZoneZulu) { if (myTimeZoneZulu) {
return TimeZone.getTimeZone("GMT"); return getTimeZone("GMT");
} }
return myTimeZone; return myTimeZone;
} }
@ -414,7 +417,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
parseInt(theWholeValue, theValue.substring(1, 3), 0, 23); parseInt(theWholeValue, theValue.substring(1, 3), 0, 23);
parseInt(theWholeValue, theValue.substring(4, 6), 0, 59); parseInt(theWholeValue, theValue.substring(4, 6), 0, 59);
myTimeZoneZulu = false; myTimeZoneZulu = false;
myTimeZone = TimeZone.getTimeZone("GMT" + theValue); myTimeZone = getTimeZone("GMT" + theValue);
} }
return this; return this;
@ -750,4 +753,8 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
} }
} }
private TimeZone getTimeZone(String offset) {
return timezoneCache.computeIfAbsent(offset, TimeZone::getTimeZone);
}
} }

View File

@ -35,7 +35,9 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.Map;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
@ -51,6 +53,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
static final long NANOS_PER_MILLIS = 1000000L; static final long NANOS_PER_MILLIS = 1000000L;
static final long NANOS_PER_SECOND = 1000000000L; static final long NANOS_PER_SECOND = 1000000000L;
private static final Map<String, TimeZone> timezoneCache = new ConcurrentHashMap<>();
private static final FastDateFormat ourHumanDateFormat = FastDateFormat.getDateInstance(FastDateFormat.MEDIUM); private static final FastDateFormat ourHumanDateFormat = FastDateFormat.getDateInstance(FastDateFormat.MEDIUM);
private static final FastDateFormat ourHumanDateTimeFormat = FastDateFormat.getDateTimeInstance(FastDateFormat.MEDIUM, FastDateFormat.MEDIUM); private static final FastDateFormat ourHumanDateTimeFormat = FastDateFormat.getDateTimeInstance(FastDateFormat.MEDIUM, FastDateFormat.MEDIUM);
@ -171,7 +174,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
} else { } else {
GregorianCalendar cal; GregorianCalendar cal;
if (myTimeZoneZulu) { if (myTimeZoneZulu) {
cal = new GregorianCalendar(TimeZone.getTimeZone("GMT")); cal = new GregorianCalendar(getTimeZone("GMT"));
} else if (myTimeZone != null) { } else if (myTimeZone != null) {
cal = new GregorianCalendar(myTimeZone); cal = new GregorianCalendar(myTimeZone);
} else { } else {
@ -336,7 +339,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
*/ */
public TimeZone getTimeZone() { public TimeZone getTimeZone() {
if (myTimeZoneZulu) { if (myTimeZoneZulu) {
return TimeZone.getTimeZone("GMT"); return getTimeZone("GMT");
} }
return myTimeZone; return myTimeZone;
} }
@ -646,7 +649,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
parseInt(theWholeValue, theValue.substring(1, 3), 0, 23); parseInt(theWholeValue, theValue.substring(1, 3), 0, 23);
parseInt(theWholeValue, theValue.substring(4, 6), 0, 59); parseInt(theWholeValue, theValue.substring(4, 6), 0, 59);
myTimeZoneZulu = false; myTimeZoneZulu = false;
myTimeZone = TimeZone.getTimeZone("GMT" + theValue); myTimeZone = getTimeZone("GMT" + theValue);
} }
return this; return this;
@ -841,4 +844,8 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
} }
} }
private TimeZone getTimeZone(String offset) {
return timezoneCache.computeIfAbsent(offset, TimeZone::getTimeZone);
}
} }

View File

@ -35,7 +35,9 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.Map;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum; import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -51,6 +53,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
static final long NANOS_PER_MILLIS = 1000000L; static final long NANOS_PER_MILLIS = 1000000L;
static final long NANOS_PER_SECOND = 1000000000L; static final long NANOS_PER_SECOND = 1000000000L;
private static final Map<String, TimeZone> timezoneCache = new ConcurrentHashMap<>();
private static final FastDateFormat ourHumanDateFormat = FastDateFormat.getDateInstance(FastDateFormat.MEDIUM); private static final FastDateFormat ourHumanDateFormat = FastDateFormat.getDateInstance(FastDateFormat.MEDIUM);
private static final FastDateFormat ourHumanDateTimeFormat = FastDateFormat.getDateTimeInstance(FastDateFormat.MEDIUM, FastDateFormat.MEDIUM); private static final FastDateFormat ourHumanDateTimeFormat = FastDateFormat.getDateTimeInstance(FastDateFormat.MEDIUM, FastDateFormat.MEDIUM);
@ -174,7 +177,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
} else { } else {
GregorianCalendar cal; GregorianCalendar cal;
if (myTimeZoneZulu) { if (myTimeZoneZulu) {
cal = new GregorianCalendar(TimeZone.getTimeZone("GMT")); cal = new GregorianCalendar(getTimeZone("GMT"));
} else if (myTimeZone != null) { } else if (myTimeZone != null) {
cal = new GregorianCalendar(myTimeZone); cal = new GregorianCalendar(myTimeZone);
} else { } else {
@ -339,7 +342,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
*/ */
public TimeZone getTimeZone() { public TimeZone getTimeZone() {
if (myTimeZoneZulu) { if (myTimeZoneZulu) {
return TimeZone.getTimeZone("GMT"); return getTimeZone("GMT");
} }
return myTimeZone; return myTimeZone;
} }
@ -645,7 +648,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
parseInt(theWholeValue, theValue.substring(1, 3), 0, 23); parseInt(theWholeValue, theValue.substring(1, 3), 0, 23);
parseInt(theWholeValue, theValue.substring(4, 6), 0, 59); parseInt(theWholeValue, theValue.substring(4, 6), 0, 59);
myTimeZoneZulu = false; myTimeZoneZulu = false;
myTimeZone = TimeZone.getTimeZone("GMT" + theValue); myTimeZone = getTimeZone("GMT" + theValue);
} }
return this; return this;
@ -944,4 +947,8 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
return "@"+primitiveValue(); return "@"+primitiveValue();
} }
private TimeZone getTimeZone(String offset) {
return timezoneCache.computeIfAbsent(offset, TimeZone::getTimeZone);
}
} }

View File

@ -42,7 +42,9 @@ import org.hl7.fhir.utilities.Utilities;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.Map;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isBlank;
@ -51,6 +53,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
static final long NANOS_PER_MILLIS = 1000000L; static final long NANOS_PER_MILLIS = 1000000L;
static final long NANOS_PER_SECOND = 1000000000L; static final long NANOS_PER_SECOND = 1000000000L;
private static final Map<String, TimeZone> timezoneCache = new ConcurrentHashMap<>();
private static final FastDateFormat ourHumanDateFormat = FastDateFormat.getDateInstance(FastDateFormat.MEDIUM); private static final FastDateFormat ourHumanDateFormat = FastDateFormat.getDateInstance(FastDateFormat.MEDIUM);
private static final FastDateFormat ourHumanDateTimeFormat = FastDateFormat.getDateTimeInstance(FastDateFormat.MEDIUM, FastDateFormat.MEDIUM); private static final FastDateFormat ourHumanDateTimeFormat = FastDateFormat.getDateTimeInstance(FastDateFormat.MEDIUM, FastDateFormat.MEDIUM);
@ -174,7 +177,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
} else { } else {
GregorianCalendar cal; GregorianCalendar cal;
if (myTimeZoneZulu) { if (myTimeZoneZulu) {
cal = new GregorianCalendar(TimeZone.getTimeZone("GMT")); cal = new GregorianCalendar(getTimeZone("GMT"));
} else if (myTimeZone != null) { } else if (myTimeZone != null) {
cal = new GregorianCalendar(myTimeZone); cal = new GregorianCalendar(myTimeZone);
} else { } else {
@ -346,7 +349,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
*/ */
public TimeZone getTimeZone() { public TimeZone getTimeZone() {
if (myTimeZoneZulu) { if (myTimeZoneZulu) {
return TimeZone.getTimeZone("GMT"); return getTimeZone("GMT");
} }
return myTimeZone; return myTimeZone;
} }
@ -652,7 +655,7 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
parseInt(theWholeValue, theValue.substring(1, 3), 0, 23); parseInt(theWholeValue, theValue.substring(1, 3), 0, 23);
parseInt(theWholeValue, theValue.substring(4, 6), 0, 59); parseInt(theWholeValue, theValue.substring(4, 6), 0, 59);
myTimeZoneZulu = false; myTimeZoneZulu = false;
myTimeZone = TimeZone.getTimeZone("GMT" + theValue); myTimeZone = getTimeZone("GMT" + theValue);
} }
return this; return this;
@ -1011,4 +1014,8 @@ public abstract class BaseDateTimeType extends PrimitiveType<Date> {
return "@"+primitiveValue(); return "@"+primitiveValue();
} }
private TimeZone getTimeZone(String offset) {
return timezoneCache.computeIfAbsent(offset, TimeZone::getTimeZone);
}
} }

View File

@ -68,7 +68,6 @@ public class TimeTracker {
c.length = c.length + System.nanoTime() - session.start; c.length = c.length + System.nanoTime() - session.start;
} }
public String report() { public String report() {
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
for (Counter c : records) { for (Counter c : records) {

View File

@ -581,20 +581,6 @@ public class ValidationMessage implements Comparator<ValidationMessage>, Compara
throw new Error("A type must be provided"); throw new Error("A type must be provided");
} }
// public ValidationMessage(Source source, IssueType type, String message, IssueSeverity level) {
// super();
// this.line = -1;
// this.col = -1;
// if (message == null)
// throw new Error("message is null");
// this.message = message;
// this.level = level;
// this.source = source;
// this.type = type;
// if (type == null)
// throw new Error("A type must be provided");
// }
private IssueSeverity determineLevel(String path) { private IssueSeverity determineLevel(String path) {
if (isGrandfathered(path)) if (isGrandfathered(path))
return IssueSeverity.WARNING; return IssueSeverity.WARNING;

View File

@ -88,7 +88,7 @@
<archive> <archive>
<manifest> <manifest>
<addClasspath>true</addClasspath> <addClasspath>true</addClasspath>
<mainClass>org.hl7.fhir.validation.Validator</mainClass> <mainClass>org.hl7.fhir.validation.ValidatorCli</mainClass>
</manifest> </manifest>
</archive> </archive>
</configuration> </configuration>

View File

@ -7,8 +7,6 @@ public class TimeTracker {
private long loadTime = 0; private long loadTime = 0;
private long fpeTime = 0; private long fpeTime = 0;
public long getOverall() { public long getOverall() {
return overall; return overall;
} }
@ -51,7 +49,5 @@ public class TimeTracker {
sdTime = 0; sdTime = 0;
loadTime = 0; loadTime = 0;
fpeTime = 0; fpeTime = 0;
} }
} }

View File

@ -7,7 +7,6 @@ import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
@ -108,39 +107,12 @@ import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
import org.hl7.fhir.utilities.validation.ValidationMessage.Source; import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
import org.hl7.fhir.utilities.xhtml.XhtmlComposer; import org.hl7.fhir.utilities.xhtml.XhtmlComposer;
import org.hl7.fhir.validation.BaseValidator.ValidationControl; import org.hl7.fhir.validation.BaseValidator.ValidationControl;
import org.hl7.fhir.validation.Validator.QuestionnaireMode; import org.hl7.fhir.validation.cli.model.ScanOutputItem;
import org.hl7.fhir.validation.cli.services.StandAloneValidatorFetcher.IPackageInstaller; import org.hl7.fhir.validation.cli.services.StandAloneValidatorFetcher.IPackageInstaller;
import org.hl7.fhir.validation.cli.utils.*;
import org.hl7.fhir.validation.instance.InstanceValidator; import org.hl7.fhir.validation.instance.InstanceValidator;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
/*
Copyright (c) 2011+, HL7, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of HL7 nor the names of its contributors may be used to
endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/* /*
Copyright (c) 2011+, HL7, Inc Copyright (c) 2011+, HL7, Inc
@ -215,81 +187,6 @@ POSSIBILITY OF SUCH DAMAGE.
*/ */
public class ValidationEngine implements IValidatorResourceFetcher, IPackageInstaller { public class ValidationEngine implements IValidatorResourceFetcher, IPackageInstaller {
public static class VersionSourceInformation {
private List<String> report = new ArrayList<>();
private List<String> versions = new ArrayList<>();
public void see(String version, String src) {
version = VersionUtilities.getMajMin(version);
report.add(src+": "+version);
if (!versions.contains(version)) {
versions.add(version);
Collections.sort(versions);
}
}
public boolean isEmpty() {
return versions.isEmpty();
}
public int size() {
return versions.size();
}
public String version() {
return versions.get(0);
}
public List<String> getReport() {
if (report.isEmpty()) {
report.add("(nothing found)");
}
return report;
}
}
public class ScanOutputItem {
private String ref;
private ImplementationGuide ig;
private StructureDefinition profile;
private OperationOutcome outcome;
private String id;
public ScanOutputItem(String ref, ImplementationGuide ig, StructureDefinition profile, OperationOutcome outcome) {
super();
this.ref = ref;
this.ig = ig;
this.profile = profile;
this.outcome = outcome;
}
public String getRef() {
return ref;
}
public ImplementationGuide getIg() {
return ig;
}
public StructureDefinition getProfile() {
return profile;
}
public OperationOutcome getOutcome() {
return outcome;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
if (profile != null)
return "Validate " +ref+" against "+profile.present()+" ("+profile.getUrl()+")";
if (ig != null)
return "Validate " +ref+" against global profile specified in "+ig.present()+" ("+ig.getUrl()+")";
return "Validate " +ref+" against FHIR Spec";
}
}
public class TransformSupportServices implements ITransformerServices { public class TransformSupportServices implements ITransformerServices {
private List<Base> outputs; private List<Base> outputs;
@ -333,7 +230,6 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
public List<Base> performSearch(Object appContext, String url) throws FHIRException { public List<Base> performSearch(Object appContext, String url) throws FHIRException {
throw new FHIRException("performSearch is not supported yet"); throw new FHIRException("performSearch is not supported yet");
} }
} }
private SimpleWorkerContext context; private SimpleWorkerContext context;
@ -360,43 +256,6 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
private Map<String, ValidationControl> validationControl = new HashMap<>(); private Map<String, ValidationControl> validationControl = new HashMap<>();
private QuestionnaireMode questionnaireMode; private QuestionnaireMode questionnaireMode;
private class AsteriskFilter implements FilenameFilter {
String dir;
String regex;
public AsteriskFilter(String filter) throws IOException {
if (!filter.matches("(.*(\\\\|\\/))*(.*)\\*(.*)"))
throw new IOException("Filter names must have the following syntax: [directorypath][prefix]?*[suffix]? I.e. The asterisk must be in the filename, not the directory path");
dir = filter.replaceAll("(.*(\\\\|\\/))*(.*)\\*(.*)", "$1");
String expression = filter.replaceAll("(.*(\\\\|\\/))*(.*)", "$3");
regex = "";
for (int i = 0; i < expression.length(); i++) {
if (Character.isAlphabetic(expression.codePointAt(i)) || Character.isDigit(expression.codePointAt(i)))
regex = regex + expression.charAt(i);
else if (expression.charAt(i)=='*')
regex = regex + ".*";
else
regex = regex + "\\" + expression.charAt(i);
}
File f = new File(dir);
if (!f.exists()) {
throw new IOException("Directory " + dir + " does not exist");
}
if (!f.isDirectory()) {
throw new IOException("Directory " + dir + " is not a directory");
}
}
public boolean accept(File dir, String s) {
boolean match = s.matches(regex);
return match;
}
public String getDir() {
return dir;
}
}
public ValidationEngine() throws IOException { public ValidationEngine() throws IOException {
pcm = new FilesystemPackageCacheManager(true, ToolsVersion.TOOLS_VERSION); pcm = new FilesystemPackageCacheManager(true, ToolsVersion.TOOLS_VERSION);
context = SimpleWorkerContext.fromNothing(); context = SimpleWorkerContext.fromNothing();
@ -423,7 +282,6 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
this.anyExtensionsAllowed = anyExtensionsAllowed; this.anyExtensionsAllowed = anyExtensionsAllowed;
} }
public boolean isShowTimes() { public boolean isShowTimes() {
return showTimes; return showTimes;
} }
@ -541,35 +399,6 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
return ep; return ep;
} }
private byte[] loadProfileSource(String src) throws FHIRException, FileNotFoundException, IOException {
if (Utilities.noString(src)) {
throw new FHIRException("Profile Source '" + src + "' could not be processed");
} else if (src.startsWith("https:") || src.startsWith("http:")) {
return loadProfileFromUrl(src);
} else if (new File(src).exists()) {
return loadProfileFromFile(src);
} else {
throw new FHIRException("Definitions Source '"+src+"' could not be processed");
}
}
private byte[] loadProfileFromUrl(String src) throws FHIRException {
try {
URL url = new URL(src+"?nocache=" + System.currentTimeMillis());
URLConnection c = url.openConnection();
return IOUtils.toByteArray(c.getInputStream());
} catch (Exception e) {
throw new FHIRException("Unable to find definitions at URL '"+src+"': "+e.getMessage(), e);
}
}
private byte[] loadProfileFromFile(String src) throws FileNotFoundException, IOException {
File f = new File(src);
if (f.isDirectory())
throw new IOException("You must provide a file name, not a directory name");
return TextFile.fileToBytes(src);
}
/** explore should be true if we're trying to load an -ig parameter, and false if we're loading source /** explore should be true if we're trying to load an -ig parameter, and false if we're loading source
* @throws IOException **/ * @throws IOException **/
@ -579,7 +408,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
// - a package id for an ig - this will be loaded into the cache // - a package id for an ig - this will be loaded into the cache
// - a direct reference to a package ("package.tgz") - this will be extracted by the cache manager, but not put in the cache // - a direct reference to a package ("package.tgz") - this will be extracted by the cache manager, but not put in the cache
// - a folder containing resources - these will be loaded directly // - a folder containing resources - these will be loaded directly
if (src.startsWith("https:") || src.startsWith("http:")) { if (Common.isNetworkPath(src)) {
String v = null; String v = null;
if (src.contains("|")) { if (src.contains("|")) {
v = src.substring(src.indexOf("|")+1); v = src.substring(src.indexOf("|")+1);
@ -621,7 +450,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
} }
private Map<String, byte[]> loadIgSourceForVersion(String src, boolean recursive, boolean explore, VersionSourceInformation versions) throws FHIRException, IOException { private Map<String, byte[]> loadIgSourceForVersion(String src, boolean recursive, boolean explore, VersionSourceInformation versions) throws FHIRException, IOException {
if (src.startsWith("https:") || src.startsWith("http:")) { if (Common.isNetworkPath(src)) {
String v = null; String v = null;
if (src.contains("|")) { if (src.contains("|")) {
v = src.substring(src.indexOf("|")+1); v = src.substring(src.indexOf("|")+1);
@ -1046,7 +875,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
if (context.hasResource(ImplementationGuide.class, src)) if (context.hasResource(ImplementationGuide.class, src))
return; return;
byte[] source = loadProfileSource(src); byte[] source = ProfileLoader.loadProfileSource(src);
FhirFormat fmt = FormatUtilities.determineFormat(source); FhirFormat fmt = FormatUtilities.determineFormat(source);
Resource r = FormatUtilities.makeParser(fmt).parse(source); Resource r = FormatUtilities.makeParser(fmt).parse(source);
context.cacheResource(r); context.cacheResource(r);
@ -1209,7 +1038,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
} }
} }
public void setQuestionnaireMode(Validator.QuestionnaireMode questionnaireMode) { public void setQuestionnaireMode(QuestionnaireMode questionnaireMode) {
this.questionnaireMode = questionnaireMode; this.questionnaireMode = questionnaireMode;
} }
@ -1273,7 +1102,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
public List<ScanOutputItem> validateScan(List<String> sources, Set<String> guides) throws FHIRException, IOException, EOperationOutcome { public List<ScanOutputItem> validateScan(List<String> sources, Set<String> guides) throws FHIRException, IOException, EOperationOutcome {
List<String> refs = new ArrayList<String>(); List<String> refs = new ArrayList<String>();
handleSources(sources, refs); parseSources(sources, refs);
List<ScanOutputItem> res = new ArrayList(); List<ScanOutputItem> res = new ArrayList();
InstanceValidator validator = getValidator(); InstanceValidator validator = getValidator();
@ -1335,10 +1164,6 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
return res; return res;
} }
private Resource resolve(Reference reference) {
return null;
}
private String getGlobal(ImplementationGuide ig, String rt) { private String getGlobal(ImplementationGuide ig, String rt) {
for (ImplementationGuideGlobalComponent igg : ig.getGlobal()) { for (ImplementationGuideGlobalComponent igg : ig.getGlobal()) {
if (rt.equals(igg.getType())) if (rt.equals(igg.getType()))
@ -1349,7 +1174,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
public void scanForVersions(List<String> sources, VersionSourceInformation versions) throws FHIRException, IOException { public void scanForVersions(List<String> sources, VersionSourceInformation versions) throws FHIRException, IOException {
List<String> refs = new ArrayList<String>(); List<String> refs = new ArrayList<String>();
handleSources(sources, refs); parseSources(sources, refs);
for (String ref : refs) { for (String ref : refs) {
Content cnt = loadContent(ref, "validate", false); Content cnt = loadContent(ref, "validate", false);
String s = TextFile.bytesToString(cnt.focus); String s = TextFile.bytesToString(cnt.focus);
@ -1373,7 +1198,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
System.out.println(" Profiles: "+profiles); System.out.println(" Profiles: "+profiles);
} }
List<String> refs = new ArrayList<String>(); List<String> refs = new ArrayList<String>();
boolean asBundle = handleSources(sources, refs); boolean asBundle = parseSources(sources, refs);
Bundle results = new Bundle(); Bundle results = new Bundle();
results.setType(Bundle.BundleType.COLLECTION); results.setType(Bundle.BundleType.COLLECTION);
for (String ref : refs) { for (String ref : refs) {
@ -1399,34 +1224,30 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
return results.getEntryFirstRep().getResource(); return results.getEntryFirstRep().getResource();
} }
/**
public OperationOutcome validateString(String location, String source, FhirFormat format, List<String> profiles) throws FHIRException, IOException, EOperationOutcome, SAXException { * Iterates through the list of passed in sources, extracting all references and populated them in the passed in list.
return validate(location, source.getBytes(), format, profiles); * @return {@link Boolean#TRUE} if more than one reference is found.
} */
public boolean parseSources(List<String> sources, List<String> refs) throws IOException {
// Public to allow reporting of results in alternate ways boolean multipleRefsFound = sources.size() > 1;
public boolean handleSources(List<String> sources, List<String> refs) throws IOException {
boolean asBundle = sources.size() > 1;
for (String source : sources) { for (String source : sources) {
if (handleSource(source, refs)) { multipleRefsFound |= extractReferences(source, refs);
asBundle = true; // Code needs to be written this way to ensure handleSource gets called
}
} }
return multipleRefsFound;
return asBundle;
} }
private boolean handleSource(String name, List<String> refs) throws IOException { /**
boolean isBundle = false; * Parses passed in resource path, adding any found references to the passed in list.
if (name.startsWith("https:") || name.startsWith("http:")) { * @return {@link Boolean#TRUE} if more than one reference is found.
*/
private boolean extractReferences(String name, List<String> refs) throws IOException {
if (Common.isNetworkPath(name)) {
refs.add(name); refs.add(name);
} else if (Common.isWildcardPath(name)) {
} else if (name.contains("*")) {
isBundle = true;
AsteriskFilter filter = new AsteriskFilter(name); AsteriskFilter filter = new AsteriskFilter(name);
File[] files = new File(filter.getDir()).listFiles(filter); File[] files = new File(filter.getDir()).listFiles(filter);
for (int i=0; i < files.length; i++) { for (File file : files) {
refs.add(files[i].getPath()); refs.add(file.getPath());
} }
} else { } else {
File file = new File(name); File file = new File(name);
@ -1442,7 +1263,6 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
if (file.isFile()) { if (file.isFile()) {
refs.add(name); refs.add(name);
} else { } else {
isBundle = true;
for (int i=0; i < file.listFiles().length; i++) { for (int i=0; i < file.listFiles().length; i++) {
File[] fileList = file.listFiles(); File[] fileList = file.listFiles();
if (fileList[i].isFile()) if (fileList[i].isFile())
@ -1450,25 +1270,21 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
} }
} }
} }
return refs.size() > 1 ;
return isBundle;
} }
public OperationOutcome validate(byte[] source, FhirFormat cntType, List<String> profiles, List<ValidationMessage> messages) throws FHIRException, IOException, EOperationOutcome { public OperationOutcome validate(byte[] source, FhirFormat cntType, List<String> profiles, List<ValidationMessage> messages) throws FHIRException, IOException, EOperationOutcome {
InstanceValidator validator = getValidator(); InstanceValidator validator = getValidator();
validator.validate(null, messages, new ByteArrayInputStream(source), cntType, asSdList(profiles)); validator.validate(null, messages, new ByteArrayInputStream(source), cntType, asSdList(profiles));
return messagesToOutcome(messages); return messagesToOutcome(messages);
} }
public OperationOutcome validate(String location, byte[] source, FhirFormat cntType, List<String> profiles) throws FHIRException, IOException, EOperationOutcome, SAXException { public OperationOutcome validate(String location, byte[] source, FhirFormat cntType, List<String> profiles) throws FHIRException, IOException, EOperationOutcome, SAXException {
List<ValidationMessage> messages = new ArrayList<ValidationMessage>(); List<ValidationMessage> messages = new ArrayList<ValidationMessage>();
if (doNative) { if (doNative) {
if (cntType == FhirFormat.JSON) SchemaValidator.validateSchema(location, cntType, messages);
validateJsonSchema(location, messages);
if (cntType == FhirFormat.XML)
validateXmlSchema(location, messages);
if (cntType == FhirFormat.TURTLE)
validateSHEX(location, messages);
} }
InstanceValidator validator = getValidator(); InstanceValidator validator = getValidator();
validator.validate(null, messages, new ByteArrayInputStream(source), cntType, asSdList(profiles)); validator.validate(null, messages, new ByteArrayInputStream(source), cntType, asSdList(profiles));
@ -1481,12 +1297,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
public OperationOutcome validate(String location, byte[] source, FhirFormat cntType, List<String> profiles, IdStatus resourceIdRule, boolean anyExtensionsAllowed, BestPracticeWarningLevel bpWarnings, CheckDisplayOption displayOption) throws FHIRException, IOException, EOperationOutcome, SAXException { public OperationOutcome validate(String location, byte[] source, FhirFormat cntType, List<String> profiles, IdStatus resourceIdRule, boolean anyExtensionsAllowed, BestPracticeWarningLevel bpWarnings, CheckDisplayOption displayOption) throws FHIRException, IOException, EOperationOutcome, SAXException {
List<ValidationMessage> messages = new ArrayList<ValidationMessage>(); List<ValidationMessage> messages = new ArrayList<ValidationMessage>();
if (doNative) { if (doNative) {
if (cntType == FhirFormat.JSON) SchemaValidator.validateSchema(location, cntType, messages);
validateJsonSchema(location, messages);
if (cntType == FhirFormat.XML)
validateXmlSchema(location, messages);
if (cntType == FhirFormat.TURTLE)
validateSHEX(location, messages);
} }
InstanceValidator validator = getValidator(); InstanceValidator validator = getValidator();
validator.setResourceIdRule(resourceIdRule); validator.setResourceIdRule(resourceIdRule);
@ -1496,39 +1307,6 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
return messagesToOutcome(messages); return messagesToOutcome(messages);
} }
private void validateSHEX(String location, List<ValidationMessage> messages) {
messages.add(new ValidationMessage(Source.InstanceValidator, IssueType.INFORMATIONAL, location, "SHEX Validation is not done yet", IssueSeverity.INFORMATION));
}
private void validateXmlSchema(String location, List<ValidationMessage> messages) throws FileNotFoundException, IOException, SAXException {
messages.add(new ValidationMessage(Source.InstanceValidator, IssueType.INFORMATIONAL, location, "XML Schema Validation is not done yet", IssueSeverity.INFORMATION));
}
private Map<String, byte[]> loadSchemas() throws IOException {
Map<String, byte[]> res = new HashMap<String, byte[]>();
for (Entry<String, byte[]> e : readZip(new ByteArrayInputStream(binaries.get("http://hl7.org/fhir#fhir-all-xsd.zip"))).entrySet()) {
if (e.getKey().equals("fhir-single.xsd"))
res.put(e.getKey(), e.getValue());
if (e.getKey().equals("fhir-invariants.sch"))
res.put(e.getKey(), e.getValue());
}
return res;
}
private Map<String, byte[]> loadTransforms() throws IOException {
Map<String, byte[]> res = new HashMap<String, byte[]>();
for (Entry<String, byte[]> e : readZip(new ByteArrayInputStream(binaries.get("http://hl7.org/fhir#fhir-all-xsd.zip"))).entrySet()) {
if (e.getKey().endsWith(".xsl"))
res.put(e.getKey(), e.getValue());
}
return res;
}
private void validateJsonSchema(String location, List<ValidationMessage> messages) {
messages.add(new ValidationMessage(Source.InstanceValidator, IssueType.INFORMATIONAL, location, "JSON Schema Validation is not done yet", IssueSeverity.INFORMATION));
}
private List<ValidationMessage> filterMessages(List<ValidationMessage> messages) { private List<ValidationMessage> filterMessages(List<ValidationMessage> messages) {
List<ValidationMessage> filteredValidation = new ArrayList<ValidationMessage>(); List<ValidationMessage> filteredValidation = new ArrayList<ValidationMessage>();
for (ValidationMessage e : messages) { for (ValidationMessage e : messages) {
@ -1566,11 +1344,6 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
return op; return op;
} }
public static String issueSummary (OperationOutcomeIssueComponent issue) {
String source = ToolingExtensions.readStringExtension(issue, ToolingExtensions.EXT_ISSUE_SOURCE);
return issue.getSeverity().toString()+" @ "+issue.getLocation() + " " +issue.getDetails().getText() +(source != null ? " (src = "+source+")" : "");
}
public org.hl7.fhir.r5.elementmodel.Element transform(String source, String map) throws FHIRException, IOException { public org.hl7.fhir.r5.elementmodel.Element transform(String source, String map) throws FHIRException, IOException {
Content cnt = loadContent(source, "validate", false); Content cnt = loadContent(source, "validate", false);
return transform(cnt.focus, cnt.cntType, map); return transform(cnt.focus, cnt.cntType, map);
@ -1764,14 +1537,14 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
Set<String> igs = new HashSet<>(); Set<String> igs = new HashSet<>();
Map<String, Set<String>> profiles = new HashMap<>(); Map<String, Set<String>> profiles = new HashMap<>();
for (ScanOutputItem item : items) { for (ScanOutputItem item : items) {
refs.add(item.ref); refs.add(item.getRef());
if (item.ig != null) { if (item.getIg() != null) {
igs.add(item.ig.getUrl()); igs.add(item.getIg().getUrl());
if (!profiles.containsKey(item.ig.getUrl())) { if (!profiles.containsKey(item.getIg().getUrl())) {
profiles.put(item.ig.getUrl(), new HashSet<>()); profiles.put(item.getIg().getUrl(), new HashSet<>());
} }
if (item.profile != null) if (item.getProfile() != null)
profiles.get(item.ig.getUrl()).add(item.profile.getUrl()); profiles.get(item.getIg().getUrl()).add(item.getProfile().getUrl());
} }
} }
@ -1846,19 +1619,17 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
b.append("</body>"); b.append("</body>");
b.append("</html>"); b.append("</html>");
TextFile.stringToFile(b.toString(), Utilities.path(folder, "scan.html")); TextFile.stringToFile(b.toString(), Utilities.path(folder, "scan.html"));
} }
private String genOutcome(List<ScanOutputItem> items, String src, String ig, String profile) { private String genOutcome(List<ScanOutputItem> items, String src, String ig, String profile) {
ScanOutputItem item = null; ScanOutputItem item = null;
for (ScanOutputItem t : items) { for (ScanOutputItem t : items) {
boolean match = true; boolean match = true;
if (!t.ref.equals(src)) if (!t.getRef().equals(src))
match = false; match = false;
if (!((ig == null && t.ig == null) || (ig != null && t.ig != null && ig.equals(t.ig.getUrl())))) if (!((ig == null && t.getIg() == null) || (ig != null && t.getIg() != null && ig.equals(t.getIg().getUrl()))))
match = false; match = false;
if (!((profile == null && t.profile == null) || (profile != null && t.profile != null && profile.equals(t.profile.getUrl())))) if (!((profile == null && t.getProfile() == null) || (profile != null && t.getProfile() != null && profile.equals(t.getProfile().getUrl()))))
match = false; match = false;
if (match) { if (match) {
item = t; item = t;
@ -1869,7 +1640,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
if (item == null) if (item == null)
return "<td></td>"; return "<td></td>";
boolean ok = true; boolean ok = true;
for (OperationOutcomeIssueComponent iss : item.outcome.getIssue()) { for (OperationOutcomeIssueComponent iss : item.getOutcome().getIssue()) {
if (iss.getSeverity() == org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR || iss.getSeverity() == org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.FATAL) { if (iss.getSeverity() == org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR || iss.getSeverity() == org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.FATAL) {
ok = false; ok = false;
} }
@ -1934,8 +1705,8 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
private void genScanOutputItem(ScanOutputItem item, String filename) throws IOException, FHIRException, EOperationOutcome { private void genScanOutputItem(ScanOutputItem item, String filename) throws IOException, FHIRException, EOperationOutcome {
RenderingContext rc = new RenderingContext(context, null, null, "http://hl7.org/fhir", "", null, ResourceRendererMode.RESOURCE); RenderingContext rc = new RenderingContext(context, null, null, "http://hl7.org/fhir", "", null, ResourceRendererMode.RESOURCE);
rc.setNoSlowLookup(true); rc.setNoSlowLookup(true);
RendererFactory.factory(item.outcome, rc).render(item.outcome); RendererFactory.factory(item.getOutcome(), rc).render(item.getOutcome());
String s = new XhtmlComposer(XhtmlComposer.HTML).compose(item.outcome.getText().getDiv()); String s = new XhtmlComposer(XhtmlComposer.HTML).compose(item.getOutcome().getText().getDiv());
String title = item.getTitle(); String title = item.getTitle();
@ -1951,10 +1722,8 @@ public class ValidationEngine implements IValidatorResourceFetcher, IPackageInst
b.append("</body>"); b.append("</body>");
b.append("</html>"); b.append("</html>");
TextFile.stringToFile(b.toString(), filename); TextFile.stringToFile(b.toString(), filename);
} }
private List<String> sorted(Set<String> keys) { private List<String> sorted(Set<String> keys) {
List<String> names = new ArrayList<String>(); List<String> names = new ArrayList<String>();
if (keys != null) if (keys != null)

View File

@ -1,244 +0,0 @@
package org.hl7.fhir.validation;
/*
Copyright (c) 2011+, HL7, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of HL7 nor the names of its contributors may be used to
endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/*
Copyright (c) 2011+, HL7, Inc
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of HL7 nor the names of its contributors may be used to
endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
import java.io.File;
import java.net.URI;
import org.hl7.fhir.r5.model.ImplementationGuide;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.utilities.TimeTracker;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.validation.ValidationEngine.VersionSourceInformation;
import org.hl7.fhir.validation.cli.ValidatorGui;
import org.hl7.fhir.validation.cli.model.CliContext;
import org.hl7.fhir.validation.cli.services.ComparisonService;
import org.hl7.fhir.validation.cli.services.ValidationService;
import org.hl7.fhir.validation.cli.utils.Common;
import org.hl7.fhir.validation.cli.utils.Display;
import org.hl7.fhir.validation.cli.utils.Params;
/**
* A executable class that will validate one or more FHIR resources against
* the specification
* <p>
* todo: schema validation (w3c xml, json schema, shex?)
* <p>
* if you want to host validation inside a process, skip this class, and look at
* ValidationEngine
* <p>
* todo: find a gome for this:
*
* @author Grahame
*/
public class Validator {
public enum EngineMode {
VALIDATION, TRANSFORM, NARRATIVE, SNAPSHOT, SCAN, CONVERT, FHIRPATH, VERSION
}
public enum QuestionnaireMode { NONE, CHECK, REQUIRED }
private static CliContext cliContext;
private static String getNamedParam(String[] args, String param) {
boolean found = false;
for (String a : args) {
if (found)
return a;
if (a.equals(param)) {
found = true;
}
}
return null;
}
private static String toMB(long maxMemory) {
return Long.toString(maxMemory / (1024 * 1024));
}
private static CliContext getCliContext() {
if (cliContext == null) {
cliContext = new CliContext();
}
return cliContext;
}
private static void goToWebPage(String url) {
try {
URI uri= new URI(url);
java.awt.Desktop.getDesktop().browse(uri);
System.out.println("Web page opened in browser");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
TimeTracker tt = new TimeTracker();
TimeTracker.Session tts = tt.start("Loading");
System.out.println("FHIR Validation tool " + VersionUtil.getVersionString());
System.out.println(" Java: " + System.getProperty("java.version") + " from " + System.getProperty("java.home") + " on " + System.getProperty("os.arch") + " (" + System.getProperty("sun.arch.data.model") + "bit). " + toMB(Runtime.getRuntime().maxMemory()) + "MB available");
String proxy = getNamedParam(args, Params.PROXY);
if (!Utilities.noString(proxy)) {
String[] p = proxy.split("\\:");
System.setProperty("http.proxyHost", p[0]);
System.setProperty("http.proxyPort", p[1]);
}
if (Params.hasParam(args, Params.GUI)) {
cliContext = Params.loadCliContext(args);
String v = Common.getVersion(args);
String definitions = VersionUtilities.packageForVersion(v) + "#" + v;
ValidationEngine validationEngine = Common.getValidationEngine(v, definitions, cliContext.getTxLog(), null);
ValidatorGui.start(cliContext, validationEngine, true);
} else if (Params.hasParam(args, Params.TEST)) {
Common.runValidationEngineTests();
} else if (args.length == 0 || Params.hasParam(args, Params.HELP) || Params.hasParam(args, "?") || Params.hasParam(args, "-?") || Params.hasParam(args, "/?")) {
Display.displayHelpDetails();
} else if (Params.hasParam(args, Params.COMPARE)) {
Display.printCliArgumentsAndInfo(args);
String dest = Params.getParam(args, Params.DESTINATION);
if (dest == null)
System.out.println("no -dest parameter provided");
else if (!new File(dest).isDirectory())
System.out.println("Specified destination (-dest parameter) is not valid: \"" + dest + "\")");
else {
// first, prepare the context
cliContext = Params.loadCliContext(args);
if (cliContext.getSv() == null) {
cliContext.setSv(determineVersion(cliContext));
}
String v = VersionUtilities.getCurrentVersion(cliContext.getSv());
String definitions = VersionUtilities.packageForVersion(v) + "#" + v;
ValidationEngine validator = ValidationService.getValidator(cliContext, definitions, tt);
ComparisonService.doLeftRightComparison(args, dest, validator);
}
} else {
Display.printCliArgumentsAndInfo(args);
cliContext = Params.loadCliContext(args);
if (cliContext.getSv() == null) {
cliContext.setSv(determineVersion(cliContext));
}
System.out.println("Loading");
// Comment this out because definitions filename doesn't necessarily contain version (and many not even be 14 characters long). Version gets spit out a couple of lines later after we've loaded the context
String definitions = VersionUtilities.packageForVersion(cliContext.getSv()) + "#" + VersionUtilities.getCurrentVersion(cliContext.getSv());
ValidationEngine validator = ValidationService.getValidator(cliContext, definitions, tt);
tts.end();
if (cliContext.getMode() == EngineMode.VERSION) {
ValidationService.transformVersion(cliContext, validator);
} else if (cliContext.getMode() == EngineMode.TRANSFORM) {
ValidationService.transform(cliContext, validator);
} else if (cliContext.getMode() == EngineMode.NARRATIVE) {
ValidationService.generateNarrative(cliContext, validator);
} else if (cliContext.getMode() == EngineMode.SNAPSHOT) {
ValidationService.generateSnapshot(cliContext, validator);
} else if (cliContext.getMode() == EngineMode.CONVERT) {
ValidationService.convertSources(cliContext, validator);
} else if (cliContext.getMode() == EngineMode.FHIRPATH) {
ValidationService.evaluateFhirpath(cliContext, validator);
} else {
for (String s : cliContext.getProfiles()) {
if (!validator.getContext().hasResource(StructureDefinition.class, s) && !validator.getContext().hasResource(ImplementationGuide.class, s)) {
System.out.println(" Fetch Profile from " + s);
validator.loadProfile(cliContext.getLocations().getOrDefault(s, s));
}
}
System.out.println("Validating");
if (cliContext.getMode() == EngineMode.SCAN) {
ValidationService.validateScan(cliContext, validator);
} else {
ValidationService.validateSources(cliContext, validator);
}
}
System.out.println("Done. "+tt.report());
}
}
public static String determineVersion(CliContext cliContext) throws Exception {
if (cliContext.getMode() != EngineMode.VALIDATION) {
return "current";
}
System.out.println("Scanning for versions (no -version parameter):");
VersionSourceInformation versions = ValidationService.scanForVersions(cliContext);
for (String s : versions.getReport()) {
System.out.println(" "+s);
}
if (versions.isEmpty()) {
System.out.println("-> Using Default version '"+VersionUtilities.CURRENT_VERSION+"'");
return "current";
}
if (versions.size() == 1) {
System.out.println("-> use version "+versions.version());
return versions.version();
}
throw new Exception("-> Multiple versions found. Specify a particular version using the -version parameter");
}
}

View File

@ -0,0 +1,199 @@
package org.hl7.fhir.validation;
/*
Copyright (c) 2011+, HL7, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of HL7 nor the names of its contributors may be used to
endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
/*
Copyright (c) 2011+, HL7, Inc
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of HL7 nor the names of its contributors may be used to
endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
import org.hl7.fhir.r5.model.ImplementationGuide;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.utilities.TimeTracker;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.validation.cli.model.CliContext;
import org.hl7.fhir.validation.cli.services.ComparisonService;
import org.hl7.fhir.validation.cli.services.ValidationService;
import org.hl7.fhir.validation.cli.utils.*;
import java.io.File;
/**
* A executable class that will validate one or more FHIR resources against
* the specification
* <p>
* todo: schema validation (w3c xml, json schema, shex?)
* <p>
* if you want to host validation inside a process, skip this class, and look at
* ValidationEngine
* <p>
* todo: find a home for this:
*
* @author Grahame
*/
public class ValidatorCli {
public static final String HTTP_PROXY_HOST = "http.proxyHost";
public static final String HTTP_PROXY_PORT = "http.proxyPort";
public static void main(String[] args) throws Exception {
TimeTracker tt = new TimeTracker();
TimeTracker.Session tts = tt.start("Loading");
Display.displayVersion();
Display.displaySystemInfo();
if (Params.hasParam(args, Params.PROXY)) {
String[] p = Params.getParam(args, Params.PROXY).split("\\:");
System.setProperty(HTTP_PROXY_HOST, p[0]);
System.setProperty(HTTP_PROXY_PORT, p[1]);
}
CliContext cliContext = Params.loadCliContext(args);
if (Params.hasParam(args, Params.TEST)) {
Common.runValidationEngineTests();
} else if (shouldDisplayHelpToUser(args)) {
Display.displayHelpDetails();
} else if (Params.hasParam(args, Params.COMPARE)) {
if (destinationDirectoryValid(Params.getParam(args, Params.DESTINATION))) {
doLeftRightComparison(args, cliContext, tt);
}
} else {
Display.printCliArgumentsAndInfo(args);
doValidation(tt, tts, cliContext);
}
}
private static boolean destinationDirectoryValid(String dest) {
if (dest == null) {
System.out.println("no -dest parameter provided");
return false;
} else if (!new File(dest).isDirectory()) {
System.out.println("Specified destination (-dest parameter) is not valid: \"" + dest + "\")");
return false;
} else {
System.out.println("Valid destination directory provided: \"" + dest + "\")");
return true;
}
}
private static boolean shouldDisplayHelpToUser(String[] args) {
return (args.length == 0
|| Params.hasParam(args, Params.HELP)
|| Params.hasParam(args, "?")
|| Params.hasParam(args, "-?")
|| Params.hasParam(args, "/?"));
}
private static void doLeftRightComparison(String[] args, CliContext cliContext, TimeTracker tt) throws Exception {
Display.printCliArgumentsAndInfo(args);
if (cliContext.getSv() == null) {
cliContext.setSv(ValidationService.determineVersion(cliContext));
}
String v = VersionUtilities.getCurrentVersion(cliContext.getSv());
String definitions = VersionUtilities.packageForVersion(v) + "#" + v;
ValidationEngine validator = ValidationService.getValidator(cliContext, definitions, tt);
ComparisonService.doLeftRightComparison(args, Params.getParam(args, Params.DESTINATION), validator);
}
private static void doValidation(TimeTracker tt, TimeTracker.Session tts, CliContext cliContext) throws Exception {
if (cliContext.getSv() == null) {
cliContext.setSv(ValidationService.determineVersion(cliContext));
}
System.out.println("Loading");
// Comment this out because definitions filename doesn't necessarily contain version (and many not even be 14 characters long).
// Version gets spit out a couple of lines later after we've loaded the context
String definitions = VersionUtilities.packageForVersion(cliContext.getSv()) + "#" + VersionUtilities.getCurrentVersion(cliContext.getSv());
ValidationEngine validator = ValidationService.getValidator(cliContext, definitions, tt);
tts.end();
switch (cliContext.getMode()) {
case TRANSFORM:
ValidationService.transform(cliContext, validator);
break;
case NARRATIVE:
ValidationService.generateNarrative(cliContext, validator);
break;
case SNAPSHOT:
ValidationService.generateSnapshot(cliContext, validator);
break;
case CONVERT:
ValidationService.convertSources(cliContext, validator);
break;
case FHIRPATH:
ValidationService.evaluateFhirpath(cliContext, validator);
break;
case VERSION:
ValidationService.transformVersion(cliContext, validator);
break;
case VALIDATION:
case SCAN:
default:
for (String s : cliContext.getProfiles()) {
if (!validator.getContext().hasResource(StructureDefinition.class, s) && !validator.getContext().hasResource(ImplementationGuide.class, s)) {
System.out.println(" Fetch Profile from " + s);
validator.loadProfile(cliContext.getLocations().getOrDefault(s, s));
}
}
System.out.println("Validating");
if (cliContext.getMode() == EngineMode.SCAN) {
ValidationService.validateScan(cliContext, validator);
} else {
ValidationService.validateSources(cliContext, validator);
}
break;
}
System.out.println("Done. " + tt.report());
}
}

View File

@ -1,30 +0,0 @@
package org.hl7.fhir.validation.cli;
import org.hl7.fhir.validation.ValidationEngine;
import org.hl7.fhir.validation.cli.controller.CliContextController;
import org.hl7.fhir.validation.cli.controller.UIController;
import org.hl7.fhir.validation.cli.controller.ValidationController;
import org.hl7.fhir.validation.cli.model.CliContext;
import io.javalin.Javalin;
public class RestEndpoints {
public UIController myUIController;
public CliContextController myCliContextController;
public ValidationController myValidationController;
public void initRestEndpoints(Javalin app, CliContext cliContext, ValidationEngine validationEngine) {
myUIController = new UIController();
myCliContextController = new CliContextController(cliContext);
myValidationController = new ValidationController(validationEngine);
app.get("/home", myUIController.renderLandingPage);
app.get("/context", myCliContextController::handleGetCurrentCliContext);
app.post("/context", myCliContextController::handleSetCurrentCliContext);
app.post("/validate", myValidationController::handleValidationRequest);
}
}

View File

@ -1,63 +0,0 @@
package org.hl7.fhir.validation.cli;
import java.awt.Desktop;
import java.net.URI;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.validation.ValidationEngine;
import org.hl7.fhir.validation.cli.model.CliContext;
import org.hl7.fhir.validation.cli.utils.Common;
import io.javalin.Javalin;
public class ValidatorGui {
private static final int GUI_FRONTEND_PORT = 8081;
private static final String PAGE_ADDRESS = "http://localhost:" + GUI_FRONTEND_PORT + "/home";
private static final String WEB_APP_FILE_LOCATION = "/public";
private static Javalin app;
private ValidatorGui(){}
/**
* N.B. this entry point, is only for testing. Please start from command line using the argument {@code -gui} for
* actual use.
*/
public static void main(String[] args) throws Exception {
CliContext cliContext = new CliContext();
String v = Common.getVersion(args);
String definitions = VersionUtilities.packageForVersion(v) + "#" + v;
ValidationEngine validationEngine = Common.getValidationEngine(v, definitions, cliContext.getTxLog(), null);
start(new CliContext(), validationEngine, false);
}
public static int getPort() {
return GUI_FRONTEND_PORT;
}
public static void start(CliContext currentContext, ValidationEngine validationEngine, boolean bootBrowser) {
app = Javalin.create();
new RestEndpoints().initRestEndpoints(app, currentContext, validationEngine);
app.config.addStaticFiles(WEB_APP_FILE_LOCATION);
app.start(GUI_FRONTEND_PORT);
if (bootBrowser) {
openBrowser();
}
}
public static void openBrowser() {
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
try {
Desktop.getDesktop().browse(new URI(PAGE_ADDRESS));
} catch (Exception e) {
System.out.println("Error opening web browser to validator GUI.\nYou can try to open the page manually at:: "
+ PAGE_ADDRESS + "\nError:: " + e.getMessage());
}
}
}
public static void stop() {
app.stop();
}
}

View File

@ -1,32 +0,0 @@
package org.hl7.fhir.validation.cli.controller;
import org.apache.http.HttpStatus;
import org.hl7.fhir.validation.cli.model.CliContext;
import org.jetbrains.annotations.NotNull;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.javalin.http.Context;
public class CliContextController {
private final String JSON_MIME_TYPE = "application/json";
private CliContext myCliContext;
public CliContextController(CliContext cliContext) {
this.myCliContext = cliContext;
}
public void handleGetCurrentCliContext(@NotNull Context ctx) throws JsonProcessingException {
ObjectMapper Obj = new ObjectMapper();
String jsonStr = Obj.writeValueAsString(myCliContext);
ctx.result(jsonStr).contentType(JSON_MIME_TYPE).status(HttpStatus.SC_OK);
}
public void handleSetCurrentCliContext(@NotNull Context ctx) {
myCliContext = ctx.bodyAsClass(CliContext.class);
ctx.status(HttpStatus.SC_OK);
}
}

View File

@ -1,13 +0,0 @@
package org.hl7.fhir.validation.cli.controller;
import io.javalin.http.Handler;
public class UIController {
public UIController() {}
public Handler renderLandingPage = ctx -> {
ctx.render("/public/index.html");
};
}

View File

@ -1,39 +0,0 @@
package org.hl7.fhir.validation.cli.controller;
import org.apache.http.HttpStatus;
import org.hl7.fhir.validation.ValidationEngine;
import org.hl7.fhir.validation.cli.model.ValidationRequest;
import org.hl7.fhir.validation.cli.model.ValidationResponse;
import org.hl7.fhir.validation.cli.services.ValidationService;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.javalin.http.Context;
public class ValidationController {
private ValidationEngine myValidationEngine;
public ValidationController(ValidationEngine validationEngine) {
this.myValidationEngine = validationEngine;
}
public void handleValidationRequest(Context ctx) {
ValidationRequest request = ctx.bodyAsClass(ValidationRequest.class);
ValidationResponse response = null;
try {
response = ValidationService.validateSources(request, myValidationEngine);
ObjectMapper Obj = new ObjectMapper();
/*
* TODO
* Write file contents to temp files to pass to validator instead of creating our own endpoint.
* Create File => new temp file
* Use Option => DeleteOnShutdown
*/
String jsonStr = Obj.writeValueAsString(response);
ctx.status(200).json(jsonStr);
} catch (Exception e) {
ctx.status(HttpStatus.SC_INTERNAL_SERVER_ERROR).result(e.getLocalizedMessage());
}
}
}

View File

@ -8,7 +8,8 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import org.hl7.fhir.r5.utils.IResourceValidator.BundleValidationRule; import org.hl7.fhir.r5.utils.IResourceValidator.BundleValidationRule;
import org.hl7.fhir.validation.Validator; import org.hl7.fhir.validation.cli.utils.QuestionnaireMode;
import org.hl7.fhir.validation.cli.utils.EngineMode;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
@ -60,7 +61,7 @@ public class CliContext {
@JsonProperty("igs") @JsonProperty("igs")
private List<String> igs = new ArrayList<String>(); private List<String> igs = new ArrayList<String>();
@JsonProperty("questionnaire") @JsonProperty("questionnaire")
private Validator.QuestionnaireMode questionnaireMode = Validator.QuestionnaireMode.CHECK; private QuestionnaireMode questionnaireMode = QuestionnaireMode.CHECK;
@JsonProperty("profiles") @JsonProperty("profiles")
private List<String> profiles = new ArrayList<String>(); private List<String> profiles = new ArrayList<String>();
@ -68,7 +69,7 @@ public class CliContext {
private List<String> sources = new ArrayList<String>(); private List<String> sources = new ArrayList<String>();
@JsonProperty("mode") @JsonProperty("mode")
private Validator.EngineMode mode = Validator.EngineMode.VALIDATION; private EngineMode mode = EngineMode.VALIDATION;
@JsonProperty("securityChecks") @JsonProperty("securityChecks")
private boolean securityChecks = false; private boolean securityChecks = false;
@ -125,12 +126,12 @@ public class CliContext {
} }
@JsonProperty("questionnaire") @JsonProperty("questionnaire")
public Validator.QuestionnaireMode getQuestionnaireMode() { public QuestionnaireMode getQuestionnaireMode() {
return questionnaireMode; return questionnaireMode;
} }
@JsonProperty("questionnaire") @JsonProperty("questionnaire")
public CliContext setQuestionnaireMode(Validator.QuestionnaireMode questionnaireMode) { public CliContext setQuestionnaireMode(QuestionnaireMode questionnaireMode) {
this.questionnaireMode = questionnaireMode; this.questionnaireMode = questionnaireMode;
return this; return this;
} }
@ -230,12 +231,12 @@ public class CliContext {
} }
@JsonProperty("mode") @JsonProperty("mode")
public Validator.EngineMode getMode() { public EngineMode getMode() {
return mode; return mode;
} }
@JsonProperty("mode") @JsonProperty("mode")
public CliContext setMode(Validator.EngineMode mode) { public CliContext setMode(EngineMode mode) {
this.mode = mode; this.mode = mode;
return this; return this;
} }
@ -494,4 +495,40 @@ public class CliContext {
public int hashCode() { public int hashCode() {
return Objects.hash(doNative, anyExtensionsAllowed, hintAboutNonMustSupport, recursive, doDebug, assumeValidRestReferences, canDoNative, noInternalCaching, noExtensibleBindingMessages, map, output, txServer, sv, txLog, mapLog, lang, fhirpath, snomedCT, targetVer, igs, questionnaireMode, profiles, sources, mode, locale, locations, crumbTrails, showTimes); return Objects.hash(doNative, anyExtensionsAllowed, hintAboutNonMustSupport, recursive, doDebug, assumeValidRestReferences, canDoNative, noInternalCaching, noExtensibleBindingMessages, map, output, txServer, sv, txLog, mapLog, lang, fhirpath, snomedCT, targetVer, igs, questionnaireMode, profiles, sources, mode, locale, locations, crumbTrails, showTimes);
} }
@Override
public String toString() {
return "CliContext{" +
"doNative=" + doNative +
", anyExtensionsAllowed=" + anyExtensionsAllowed +
", hintAboutNonMustSupport=" + hintAboutNonMustSupport +
", recursive=" + recursive +
", doDebug=" + doDebug +
", assumeValidRestReferences=" + assumeValidRestReferences +
", canDoNative=" + canDoNative +
", noInternalCaching=" + noInternalCaching +
", noExtensibleBindingMessages=" + noExtensibleBindingMessages +
", map='" + map + '\'' +
", output='" + output + '\'' +
", txServer='" + txServer + '\'' +
", sv='" + sv + '\'' +
", txLog='" + txLog + '\'' +
", mapLog='" + mapLog + '\'' +
", lang='" + lang + '\'' +
", fhirpath='" + fhirpath + '\'' +
", snomedCT='" + snomedCT + '\'' +
", targetVer='" + targetVer + '\'' +
", igs=" + igs +
", questionnaireMode=" + questionnaireMode +
", profiles=" + profiles +
", sources=" + sources +
", mode=" + mode +
", securityChecks=" + securityChecks +
", crumbTrails=" + crumbTrails +
", showTimes=" + showTimes +
", locale='" + locale + '\'' +
", locations=" + locations +
", bundleValidationRules=" + bundleValidationRules +
'}';
}
} }

View File

@ -0,0 +1,53 @@
package org.hl7.fhir.validation.cli.model;
import org.hl7.fhir.r5.model.ImplementationGuide;
import org.hl7.fhir.r5.model.OperationOutcome;
import org.hl7.fhir.r5.model.StructureDefinition;
public class ScanOutputItem {
private String ref;
private ImplementationGuide ig;
private StructureDefinition profile;
private OperationOutcome outcome;
private String id;
public ScanOutputItem(String ref, ImplementationGuide ig, StructureDefinition profile, OperationOutcome outcome) {
super();
this.ref = ref;
this.ig = ig;
this.profile = profile;
this.outcome = outcome;
}
public String getRef() {
return ref;
}
public ImplementationGuide getIg() {
return ig;
}
public StructureDefinition getProfile() {
return profile;
}
public OperationOutcome getOutcome() {
return outcome;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
if (profile != null)
return "Validate " + ref + " against " + profile.present() + " (" + profile.getUrl() + ")";
if (ig != null)
return "Validate " + ref + " against global profile specified in " + ig.present() + " (" + ig.getUrl() + ")";
return "Validate " + ref + " against FHIR Spec";
}
}

View File

@ -21,8 +21,8 @@ import org.hl7.fhir.utilities.npm.NpmPackage;
public class StandAloneValidatorFetcher implements IValidatorResourceFetcher { public class StandAloneValidatorFetcher implements IValidatorResourceFetcher {
public interface IPackageInstaller { public interface IPackageInstaller {
public boolean packageExists(String id, String ver) throws IOException, FHIRException; boolean packageExists(String id, String ver) throws IOException, FHIRException;
public void loadPackage(String id, String ver) throws IOException, FHIRException; void loadPackage(String id, String ver) throws IOException, FHIRException;
} }
private BasePackageCacheManager pcm; private BasePackageCacheManager pcm;

View File

@ -24,26 +24,22 @@ import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.TimeTracker; import org.hl7.fhir.utilities.TimeTracker;
import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.validation.ValidationEngine; import org.hl7.fhir.validation.ValidationEngine;
import org.hl7.fhir.validation.ValidationEngine.VersionSourceInformation; import org.hl7.fhir.validation.cli.model.*;
import org.hl7.fhir.validation.cli.model.CliContext; import org.hl7.fhir.validation.cli.utils.EngineMode;
import org.hl7.fhir.validation.cli.model.FileInfo; import org.hl7.fhir.validation.cli.utils.VersionSourceInformation;
import org.hl7.fhir.validation.cli.model.ValidationOutcome;
import org.hl7.fhir.validation.cli.model.ValidationRequest;
import org.hl7.fhir.validation.cli.model.ValidationResponse;
public class ValidationService { public class ValidationService {
/* public static ValidationResponse validateSources(ValidationRequest request) throws Exception {
* TEMPORARY METHOD if (request.getCliContext().getSv() == null) {
*/ request.getCliContext().setSv(ValidationService.determineVersion(request.getCliContext()));
public static void validateFileInfo(FileInfo f) { }
System.out.println("success"); String definitions = VersionUtilities.packageForVersion(request.getCliContext().getSv()) + "#" + VersionUtilities.getCurrentVersion(request.getCliContext().getSv());
} ValidationEngine validator = ValidationService.getValidator(request.getCliContext(), definitions, new TimeTracker());
public static ValidationResponse validateSources(ValidationRequest request, ValidationEngine validator) throws Exception {
if (request.getCliContext().getProfiles().size() > 0) { if (request.getCliContext().getProfiles().size() > 0) {
System.out.println(" .. validate " + request.listSourceFiles() + " against " + request.getCliContext().getProfiles().toString()); System.out.println(" .. validate " + request.listSourceFiles() + " against " + request.getCliContext().getProfiles().toString());
} else { } else {
@ -110,7 +106,7 @@ public class ValidationService {
if (ig.getUrl().contains("/ImplementationGuide") && !ig.getUrl().equals("http://hl7.org/fhir/ImplementationGuide/fhir")) if (ig.getUrl().contains("/ImplementationGuide") && !ig.getUrl().equals("http://hl7.org/fhir/ImplementationGuide/fhir"))
urls.add(ig.getUrl()); urls.add(ig.getUrl());
} }
List<ValidationEngine.ScanOutputItem> res = validator.validateScan(cliContext.getSources(), urls); List<ScanOutputItem> res = validator.validateScan(cliContext.getSources(), urls);
validator.genScanOutput(cliContext.getOutput(), res); validator.genScanOutput(cliContext.getOutput(), res);
System.out.println("Done. output in " + Utilities.path(cliContext.getOutput(), "scan.html")); System.out.println("Done. output in " + Utilities.path(cliContext.getOutput(), "scan.html"));
} }
@ -284,4 +280,24 @@ public class ValidationService {
} }
return " " + issue.getSeverity().getDisplay() + " @ " + loc + " : " + issue.getDetails().getText(); return " " + issue.getSeverity().getDisplay() + " @ " + loc + " : " + issue.getDetails().getText();
} }
public static String determineVersion(CliContext cliContext) throws Exception {
if (cliContext.getMode() != EngineMode.VALIDATION) {
return "current";
}
System.out.println("Scanning for versions (no -version parameter):");
VersionSourceInformation versions = ValidationService.scanForVersions(cliContext);
for (String s : versions.getReport()) {
System.out.println(" " + s);
}
if (versions.isEmpty()) {
System.out.println("-> Using Default version '" + VersionUtilities.CURRENT_VERSION + "'");
return "current";
}
if (versions.size() == 1) {
System.out.println("-> use version " + versions.version());
return versions.version();
}
throw new Exception("-> Multiple versions found. Specify a particular version using the -version parameter");
}
} }

View File

@ -0,0 +1,41 @@
package org.hl7.fhir.validation.cli.utils;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
public class AsteriskFilter implements FilenameFilter {
String dir;
String regex;
public AsteriskFilter(String filter) throws IOException {
if (!filter.matches("(.*(\\\\|\\/))*(.*)\\*(.*)"))
throw new IOException("Filter names must have the following syntax: [directorypath][prefix]?*[suffix]? I.e. The asterisk must be in the filename, not the directory path");
dir = filter.replaceAll("(.*(\\\\|\\/))*(.*)\\*(.*)", "$1");
String expression = filter.replaceAll("(.*(\\\\|\\/))*(.*)", "$3");
regex = "";
for (int i = 0; i < expression.length(); i++) {
if (Character.isAlphabetic(expression.codePointAt(i)) || Character.isDigit(expression.codePointAt(i)))
regex = regex + expression.charAt(i);
else if (expression.charAt(i) == '*')
regex = regex + ".*";
else
regex = regex + "\\" + expression.charAt(i);
}
File f = new File(dir);
if (!f.exists()) {
throw new IOException("Directory " + dir + " does not exist");
}
if (!f.isDirectory()) {
throw new IOException("Directory " + dir + " is not a directory");
}
}
public boolean accept(File dir, String s) {
return s.matches(regex);
}
public String getDir() {
return dir;
}
}

View File

@ -92,4 +92,12 @@ public class Common {
return ve; return ve;
} }
public static boolean isNetworkPath(String path) {
return path.startsWith("https:") || path.startsWith("http:");
}
public static boolean isWildcardPath(String name) {
return name.contains("*");
}
} }

View File

@ -1,19 +1,23 @@
package org.hl7.fhir.validation.cli.utils; package org.hl7.fhir.validation.cli.utils;
import java.io.IOException; import org.apache.commons.io.FileUtils;
import org.hl7.fhir.r5.model.Constants;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
import org.hl7.fhir.utilities.npm.ToolsVersion; import org.hl7.fhir.utilities.npm.ToolsVersion;
import java.io.File;
import java.io.IOException;
/** /**
* Class for displaying output to the cli user. * Class for displaying output to the cli user.
* * <p>
* TODO - Clean this up for localization * TODO - Clean this up for localization
*/ */
public class Display { public class Display {
private static String toMB(long maxMemory) {
return Long.toString(maxMemory / (1024 * 1024));
}
public static void printCliArgumentsAndInfo(String[] args) throws IOException { public static void printCliArgumentsAndInfo(String[] args) throws IOException {
System.out.println(" Paths: Current = " + System.getProperty("user.dir") + ", Package Cache = " + new FilesystemPackageCacheManager(true, ToolsVersion.TOOLS_VERSION).getFolder()); System.out.println(" Paths: Current = " + System.getProperty("user.dir") + ", Package Cache = " + new FilesystemPackageCacheManager(true, ToolsVersion.TOOLS_VERSION).getFolder());
System.out.print(" Params:"); System.out.print(" Params:");
@ -23,128 +27,35 @@ public class Display {
System.out.println(); System.out.println();
} }
/**
* Loads the help details from resources/help.txt, and displays them on the command line to the user.
*/
public static void displayHelpDetails() { public static void displayHelpDetails() {
System.out.println(""); ClassLoader classLoader = Display.class.getClassLoader();
System.out.println("The FHIR validation tool validates a FHIR resource or bundle."); File file = new File(classLoader.getResource("help.txt").getFile());
System.out.println("The validation tool compares a resource against the base definitions and any"); try {
System.out.println("profiles declared in the resource (Resource.meta.profile) or specified on the "); String data = FileUtils.readFileToString(file, "UTF-8");
System.out.println("command line"); System.out.println(data);
System.out.println(""); } catch (IOException e) {
System.out.println("The FHIR validation tool validates a FHIR resource or bundle."); e.printStackTrace();
System.out.println("Schema and schematron checking is performed, then some additional checks are performed. "); }
System.out.println("* XML & Json (FHIR versions 1.0, 1.4, 3.0, 4.0, " + Constants.VERSION_MM + ")");
System.out.println("* Turtle (FHIR versions 3.0, 4.0, " + Constants.VERSION_MM + ")");
System.out.println("");
System.out.println("If requested, instances will also be verified against the appropriate schema");
System.out.println("W3C XML Schema, JSON schema or ShEx, as appropriate");
System.out.println("");
System.out.println("Usage: java -jar [validator].jar (parameters)");
System.out.println("");
System.out.println("The following parameters are supported:");
System.out.println("[source]: a file, url, directory or pattern for resources to validate. At");
System.out.println(" least one source must be declared. If there is more than one source or if");
System.out.println(" the source is other than a single file or url and the output parameter is");
System.out.println(" used, results will be provided as a Bundle.");
System.out.println(" Patterns are limited to a directory followed by a filename with an embedded");
System.out.println(" asterisk. E.g. foo*-examples.xml or someresource.*, etc.");
System.out.println("-version [ver]: The FHIR version to use. This can only appear once. ");
System.out.println(" valid values 1.0 | 1.4 | 3.0 | " + VersionUtilities.CURRENT_VERSION + " or 1.0.2 | 1.4.0 | 3.0.2 | 4.0.1 | " + VersionUtilities.CURRENT_FULL_VERSION);
System.out.println(" Default value is " + VersionUtilities.CURRENT_VERSION);
System.out.println("-ig [package|file|folder|url]: an IG or profile definition to load. Can be ");
System.out.println(" the URL of an implementation guide or a package ([id]-[ver]) for");
System.out.println(" a built implementation guide or a local folder that contains a");
System.out.println(" set of conformance resources.");
System.out.println(" No default value. This parameter can appear any number of times");
System.out.println("-tx [url]: the [base] url of a FHIR terminology service");
System.out.println(" Default value is http://tx.fhir.org. This parameter can appear once");
System.out.println(" To run without terminology value, specific n/a as the URL");
System.out.println("-txLog [file]: Produce a log of the terminology server operations in [file]");
System.out.println(" Default value is not to produce a log");
System.out.println("-profile [url]: the canonical URL to validate against (same as if it was ");
System.out.println(" specified in Resource.meta.profile). If no profile is specified, the ");
System.out.println(" resource is validated against the base specification. This parameter ");
System.out.println(" can appear any number of times.");
System.out.println(" Note: the profile (and it's dependencies) have to be made available ");
System.out.println(" through one of the -ig parameters. Note that package dependencies will ");
System.out.println(" automatically be resolved");
System.out.println("-questionnaire [file|url}: the location of a questionnaire. If provided, then the validator will validate");
System.out.println(" any QuestionnaireResponse that claims to match the Questionnaire against it");
System.out.println(" no default value. This parameter can appear any number of times");
System.out.println("-output [file]: a filename for the results (OperationOutcome)");
System.out.println(" Default: results are sent to the std out.");
System.out.println("-debug");
System.out.println(" Produce additional information about the loading/validation process");
System.out.println("-recurse");
System.out.println(" Look in subfolders when -ig refers to a folder");
System.out.println("-locale");
System.out.println(" Specifies the locale/language of the validation result messages (eg.: de-DE");
System.out.println("-sct");
System.out.println(" Specify the edition of SNOMED CT to use. Valid Choices:");
System.out.println(" intl | us | uk | au | nl | ca | se | dk | es");
System.out.println(" tx.fhir.org only supports a subset. To add to this list or tx.fhir.org");
System.out.println(" ask on https://chat.fhir.org/#narrow/stream/179202-terminology");
System.out.println("-native: use schema for validation as well");
System.out.println(" * XML: w3c schema+schematron");
System.out.println(" * JSON: json.schema");
System.out.println(" * RDF: SHEX");
System.out.println(" Default: false");
System.out.println("-language: [lang]");
System.out.println(" The language to use when validating coding displays - same value as for xml:lang");
System.out.println(" Not used if the resource specifies language");
System.out.println(" Default: no specified language");
System.out.println("-strictExtensions: If present, treat extensions not defined within the specified FHIR version and any");
System.out.println(" referenced implementation guides or profiles as errors. (Default is to only raise information messages.)");
System.out.println("-hintAboutNonMustSupport: If present, raise hints if the instance contains data elements that are not");
System.out.println(" marked as mustSupport=true. Useful to identify elements included that may be ignored by recipients");
System.out.println("-assumeValidRestReferences: If present, assume that URLs that reference resources follow the RESTful URI pattern");
System.out.println(" and it is safe to infer the type from the URL");
System.out.println("-security-checks: If present, check that string content doesn't include any html-like tags that might create");
System.out.println(" problems downstream (though all external input must always be santized by escaping for either html or sql)");
System.out.println("");
System.out.println("The validator also supports the param -proxy=[address]:[port] for if you use a proxy");
System.out.println("");
System.out.println("Parameters can appear in any order");
System.out.println("");
System.out.println("Alternatively, you can use the validator to execute a transformation as described by a structure map.");
System.out.println("To do this, you must provide some additional parameters:");
System.out.println("");
System.out.println(" -transform [map]");
System.out.println("");
System.out.println("* [map] the URI of the map that the transform starts with");
System.out.println("");
System.out.println("Any other dependency maps have to be loaded through an -ig reference ");
System.out.println("");
System.out.println("-transform uses the parameters -defn, -txserver, -ig (at least one with the map files), and -output");
System.out.println("");
System.out.println("Alternatively, you can use the validator to generate narrative for a resource.");
System.out.println("To do this, you must provide a specific parameter:");
System.out.println("");
System.out.println(" -narrative");
System.out.println("");
System.out.println("-narrative requires the parameters -defn, -txserver, -source, and -output. ig and profile may be used");
System.out.println("");
System.out.println("Alternatively, you can use the validator to convert a resource or logical model.");
System.out.println("To do this, you must provide a specific parameter:");
System.out.println("");
System.out.println(" -convert");
System.out.println("");
System.out.println("-convert requires the parameters -source and -output. ig may be used to provide a logical model");
System.out.println("");
System.out.println("Alternatively, you can use the validator to evaluate a FHIRPath expression on a resource or logical model.");
System.out.println("To do this, you must provide a specific parameter:");
System.out.println("");
System.out.println(" -fhirpath [FHIRPath]");
System.out.println("");
System.out.println("* [FHIRPath] the FHIRPath expression to evaluate");
System.out.println("");
System.out.println("-fhirpath requires the parameters -source. ig may be used to provide a logical model");
System.out.println("");
System.out.println("Finally, you can use the validator to generate a snapshot for a profile.");
System.out.println("To do this, you must provide a specific parameter:");
System.out.println("");
System.out.println(" -snapshot");
System.out.println("");
System.out.println("-snapshot requires the parameters -defn, -txserver, -source, and -output. ig may be used to provide necessary base profiles");
} }
/**
* Prints out system info to the command line.
*/
public static void displaySystemInfo() {
System.out.println(" Java: " + System.getProperty("java.version")
+ " from " + System.getProperty("java.home")
+ " on " + System.getProperty("os.arch")
+ " (" + System.getProperty("sun.arch.data.model") + "bit). "
+ toMB(Runtime.getRuntime().maxMemory()) + "MB available");
}
/**
* Prints current version of the validator.
*/
public static void displayVersion() {
System.out.println("FHIR Validation tool " + VersionUtil.getVersionString());
}
} }

View File

@ -1,4 +1,6 @@
export const EngineMode { package org.hl7.fhir.validation.cli.utils;
public enum EngineMode {
VALIDATION, VALIDATION,
TRANSFORM, TRANSFORM,
NARRATIVE, NARRATIVE,

View File

@ -1,17 +1,15 @@
package org.hl7.fhir.validation.cli.utils; package org.hl7.fhir.validation.cli.utils;
import org.hl7.fhir.r5.utils.IResourceValidator.BundleValidationRule;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.validation.cli.model.CliContext;
import java.io.File; import java.io.File;
import java.util.Arrays; import java.util.Arrays;
import java.util.Locale; import java.util.Locale;
import org.hl7.fhir.r5.utils.IResourceValidator.BundleValidationRule;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.validation.Validator;
import org.hl7.fhir.validation.cli.model.CliContext;
public class Params { public class Params {
public static final String GUI = "-gui";
public static final String VERSION = "-version"; public static final String VERSION = "-version";
public static final String OUTPUT = "-output"; public static final String OUTPUT = "-output";
public static final String PROXY = "-proxy"; public static final String PROXY = "-proxy";
@ -74,9 +72,9 @@ public class Params {
* @return {@link String} value for the provided param. * @return {@link String} value for the provided param.
*/ */
public static String getParam(String[] args, String param) { public static String getParam(String[] args, String param) {
for (int i = 0; i < args.length - 1; i++) for (int i = 0; i < args.length - 1; i++) {
if (args[i].equals(param)) if (args[i].equals(param)) return args[i + 1];
return args[i + 1]; }
return null; return null;
} }
@ -124,7 +122,7 @@ public class Params {
throw new Error("Specified -questionnaire without indicating questionnaire file"); throw new Error("Specified -questionnaire without indicating questionnaire file");
else { else {
String q = args[++i]; String q = args[++i];
cliContext.setQuestionnaireMode(Validator.QuestionnaireMode.valueOf(q)); cliContext.setQuestionnaireMode(QuestionnaireMode.valueOf(q));
} }
} else if (args[i].equals(NATIVE)) { } else if (args[i].equals(NATIVE)) {
cliContext.setDoNative(true); cliContext.setDoNative(true);
@ -152,18 +150,18 @@ public class Params {
cliContext.setHintAboutNonMustSupport(true); cliContext.setHintAboutNonMustSupport(true);
} else if (args[i].equals(TO_VERSION)) { } else if (args[i].equals(TO_VERSION)) {
cliContext.setTargetVer(args[++i]); cliContext.setTargetVer(args[++i]);
cliContext.setMode(Validator.EngineMode.VERSION); cliContext.setMode(EngineMode.VERSION);
} else if (args[i].equals(DO_NATIVE)) { } else if (args[i].equals(DO_NATIVE)) {
cliContext.setCanDoNative(true); cliContext.setCanDoNative(true);
} else if (args[i].equals(NO_NATIVE)) { } else if (args[i].equals(NO_NATIVE)) {
cliContext.setCanDoNative(false); cliContext.setCanDoNative(false);
} else if (args[i].equals(TRANSFORM)) { } else if (args[i].equals(TRANSFORM)) {
cliContext.setMap(args[++i]); cliContext.setMap(args[++i]);
cliContext.setMode(Validator.EngineMode.TRANSFORM); cliContext.setMode(EngineMode.TRANSFORM);
} else if (args[i].equals(NARRATIVE)) { } else if (args[i].equals(NARRATIVE)) {
cliContext.setMode(Validator.EngineMode.NARRATIVE); cliContext.setMode(EngineMode.NARRATIVE);
} else if (args[i].equals(SNAPSHOT)) { } else if (args[i].equals(SNAPSHOT)) {
cliContext.setMode(Validator.EngineMode.SNAPSHOT); cliContext.setMode(EngineMode.SNAPSHOT);
} else if (args[i].equals(SECURITY_CHECKS)) { } else if (args[i].equals(SECURITY_CHECKS)) {
cliContext.setSecurityChecks(true); cliContext.setSecurityChecks(true);
} else if (args[i].equals(CRUMB_TRAIL)) { } else if (args[i].equals(CRUMB_TRAIL)) {
@ -171,7 +169,7 @@ public class Params {
} else if (args[i].equals(SHOW_TIMES)) { } else if (args[i].equals(SHOW_TIMES)) {
cliContext.setShowTimes(true); cliContext.setShowTimes(true);
} else if (args[i].equals(SCAN)) { } else if (args[i].equals(SCAN)) {
cliContext.setMode(Validator.EngineMode.SCAN); cliContext.setMode(EngineMode.SCAN);
} else if (args[i].equals(TERMINOLOGY)) { } else if (args[i].equals(TERMINOLOGY)) {
if (i + 1 == args.length) if (i + 1 == args.length)
throw new Error("Specified -tx without indicating terminology server"); throw new Error("Specified -tx without indicating terminology server");
@ -216,9 +214,9 @@ public class Params {
} else if (args[i].startsWith(X)) { } else if (args[i].startsWith(X)) {
i++; i++;
} else if (args[i].equals(CONVERT)) { } else if (args[i].equals(CONVERT)) {
cliContext.setMode(Validator.EngineMode.CONVERT); cliContext.setMode(EngineMode.CONVERT);
} else if (args[i].equals(FHIRPATH)) { } else if (args[i].equals(FHIRPATH)) {
cliContext.setMode(Validator.EngineMode.FHIRPATH); cliContext.setMode(EngineMode.FHIRPATH);
if (cliContext.getFhirpath() == null) if (cliContext.getFhirpath() == null)
if (i + 1 == args.length) if (i + 1 == args.length)
throw new Error("Specified -fhirpath without indicating a FHIRPath expression"); throw new Error("Specified -fhirpath without indicating a FHIRPath expression");

View File

@ -0,0 +1,43 @@
package org.hl7.fhir.validation.cli.utils;
import org.apache.commons.io.IOUtils;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
public class ProfileLoader {
public static byte[] loadProfileSource(String src) throws FHIRException, IOException {
if (Utilities.noString(src)) {
throw new FHIRException("Profile Source '" + src + "' could not be processed");
} else if (Common.isNetworkPath(src)) {
return loadProfileFromUrl(src);
} else if (new File(src).exists()) {
return loadProfileFromFile(src);
} else {
throw new FHIRException("Definitions Source '" + src + "' could not be processed");
}
}
private static byte[] loadProfileFromUrl(String src) throws FHIRException {
try {
URL url = new URL(src + "?nocache=" + System.currentTimeMillis());
URLConnection c = url.openConnection();
return IOUtils.toByteArray(c.getInputStream());
} catch (Exception e) {
throw new FHIRException("Unable to find definitions at URL '" + src + "': " + e.getMessage(), e);
}
}
private static byte[] loadProfileFromFile(String src) throws IOException {
File f = new File(src);
if (f.isDirectory())
throw new IOException("You must provide a file name, not a directory name");
return TextFile.fileToBytes(src);
}
}

View File

@ -0,0 +1,7 @@
package org.hl7.fhir.validation.cli.utils;
public enum QuestionnaireMode {
NONE,
CHECK,
REQUIRED
}

View File

@ -0,0 +1,33 @@
package org.hl7.fhir.validation.cli.utils;
import org.hl7.fhir.r5.elementmodel.Manager;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.xml.sax.SAXException;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
public class SchemaValidator {
public static void validateSchema(String location, Manager.FhirFormat cntType, List<ValidationMessage> messages) throws IOException, SAXException {
if (cntType == Manager.FhirFormat.JSON)
validateJsonSchema(location, messages);
if (cntType == Manager.FhirFormat.XML)
validateXmlSchema(location, messages);
if (cntType == Manager.FhirFormat.TURTLE)
validateSHEX(location, messages);
}
private static void validateSHEX(String location, List<ValidationMessage> messages) {
messages.add(new ValidationMessage(ValidationMessage.Source.InstanceValidator, ValidationMessage.IssueType.INFORMATIONAL, location, "SHEX Validation is not done yet", ValidationMessage.IssueSeverity.INFORMATION));
}
private static void validateXmlSchema(String location, List<ValidationMessage> messages) throws FileNotFoundException, IOException, SAXException {
messages.add(new ValidationMessage(ValidationMessage.Source.InstanceValidator, ValidationMessage.IssueType.INFORMATIONAL, location, "XML Schema Validation is not done yet", ValidationMessage.IssueSeverity.INFORMATION));
}
private static void validateJsonSchema(String location, List<ValidationMessage> messages) {
messages.add(new ValidationMessage(ValidationMessage.Source.InstanceValidator, ValidationMessage.IssueType.INFORMATIONAL, location, "JSON Schema Validation is not done yet", ValidationMessage.IssueSeverity.INFORMATION));
}
}

View File

@ -0,0 +1,41 @@
package org.hl7.fhir.validation.cli.utils;
import org.hl7.fhir.utilities.VersionUtilities;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class VersionSourceInformation {
private List<String> report = new ArrayList<>();
private List<String> versions = new ArrayList<>();
public void see(String version, String src) {
version = VersionUtilities.getMajMin(version);
report.add(src + ": " + version);
if (!versions.contains(version)) {
versions.add(version);
Collections.sort(versions);
}
}
public boolean isEmpty() {
return versions.isEmpty();
}
public int size() {
return versions.size();
}
public String version() {
return versions.get(0);
}
public List<String> getReport() {
if (report.isEmpty()) {
report.add("(nothing found)");
}
return report;
}
}

View File

@ -1,4 +1,4 @@
package org.hl7.fhir.validation; package org.hl7.fhir.validation.cli.utils;
import static org.apache.commons.lang3.StringUtils.defaultIfBlank; import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
import static org.apache.commons.lang3.StringUtils.left; import static org.apache.commons.lang3.StringUtils.left;

View File

@ -147,7 +147,7 @@ import org.hl7.fhir.utilities.validation.ValidationOptions;
import org.hl7.fhir.utilities.xhtml.NodeType; import org.hl7.fhir.utilities.xhtml.NodeType;
import org.hl7.fhir.utilities.xhtml.XhtmlNode; import org.hl7.fhir.utilities.xhtml.XhtmlNode;
import org.hl7.fhir.validation.BaseValidator; import org.hl7.fhir.validation.BaseValidator;
import org.hl7.fhir.validation.Validator.QuestionnaireMode; import org.hl7.fhir.validation.cli.utils.QuestionnaireMode;
import org.hl7.fhir.validation.instance.type.BundleValidator; import org.hl7.fhir.validation.instance.type.BundleValidator;
import org.hl7.fhir.validation.instance.type.CodeSystemValidator; import org.hl7.fhir.validation.instance.type.CodeSystemValidator;
import org.hl7.fhir.validation.instance.type.MeasureValidator; import org.hl7.fhir.validation.instance.type.MeasureValidator;

View File

@ -43,8 +43,8 @@ import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
import org.hl7.fhir.utilities.validation.ValidationMessage.Source; import org.hl7.fhir.utilities.validation.ValidationMessage.Source;
import org.hl7.fhir.utilities.validation.ValidationOptions; import org.hl7.fhir.utilities.validation.ValidationOptions;
import org.hl7.fhir.validation.BaseValidator; import org.hl7.fhir.validation.BaseValidator;
import org.hl7.fhir.validation.cli.utils.QuestionnaireMode;
import org.hl7.fhir.validation.TimeTracker; import org.hl7.fhir.validation.TimeTracker;
import org.hl7.fhir.validation.Validator.QuestionnaireMode;
import org.hl7.fhir.validation.instance.EnableWhenEvaluator; import org.hl7.fhir.validation.instance.EnableWhenEvaluator;
import org.hl7.fhir.validation.instance.EnableWhenEvaluator.QStack; import org.hl7.fhir.validation.instance.EnableWhenEvaluator.QStack;
import org.hl7.fhir.validation.instance.utils.NodeStack; import org.hl7.fhir.validation.instance.utils.NodeStack;
@ -86,7 +86,6 @@ public class QuestionnaireValidator extends BaseValidator {
} }
} }
private void validateQuestionnaireElement(List<ValidationMessage> errors, NodeStack ns, Element questionnaire, Element item, List<Element> parents) { private void validateQuestionnaireElement(List<ValidationMessage> errors, NodeStack ns, Element questionnaire, Element item, List<Element> parents) {
// R4+ // R4+
if ((FHIRVersion.isR4Plus(context.getVersion())) && (item.hasChildren("enableWhen"))) { if ((FHIRVersion.isR4Plus(context.getVersion())) && (item.hasChildren("enableWhen"))) {

View File

@ -0,0 +1,121 @@
The FHIR validation tool validates a FHIR resource or bundle.
The validation tool compares a resource against the base definitions and any
profiles declared in the resource (Resource.meta.profile) or specified on the
command line
The FHIR validation tool validates a FHIR resource or bundle.
Schema and schematron checking is performed, then some additional checks are performed.
* XML & Json (FHIR versions 1.0, 1.4, 3.0, 4.0, " + Constants.VERSION_MM + ")
* Turtle (FHIR versions 3.0, 4.0, " + Constants.VERSION_MM + ")
If requested, instances will also be verified against the appropriate schema
W3C XML Schema, JSON schema or ShEx, as appropriate
Usage: java -jar [validator].jar (parameters)
The following parameters are supported:
[source]: a file, url, directory or pattern for resources to validate. At
least one source must be declared. If there is more than one source or if
the source is other than a single file or url and the output parameter is
used, results will be provided as a Bundle.
Patterns are limited to a directory followed by a filename with an embedded
asterisk. E.g. foo*-examples.xml or someresource.*, etc.
-version [ver]: The FHIR version to use. This can only appear once.
valid values 1.0 | 1.4 | 3.0 | " + VersionUtilities.CURRENT_VERSION + " or 1.0.2 | 1.4.0 | 3.0.2 | 4.0.1 | " + VersionUtilities.CURRENT_FULL_VERSION);
Default value is " + VersionUtilities.CURRENT_VERSION);
-ig [package|file|folder|url]: an IG or profile definition to load. Can be
the URL of an implementation guide or a package ([id]-[ver]) for
a built implementation guide or a local folder that contains a
set of conformance resources.
No default value. This parameter can appear any number of times
-tx [url]: the [base] url of a FHIR terminology service
Default value is http://tx.fhir.org. This parameter can appear once
To run without terminology value, specific n/a as the URL
-txLog [file]: Produce a log of the terminology server operations in [file]
Default value is not to produce a log
-profile [url]: the canonical URL to validate against (same as if it was
specified in Resource.meta.profile). If no profile is specified, the
resource is validated against the base specification. This parameter
can appear any number of times.
Note: the profile (and it's dependencies) have to be made available
through one of the -ig parameters. Note that package dependencies will
automatically be resolved
-questionnaire [file|url}: the location of a questionnaire. If provided, then the validator will validate
any QuestionnaireResponse that claims to match the Questionnaire against it
no default value. This parameter can appear any number of times
-output [file]: a filename for the results (OperationOutcome)
Default: results are sent to the std out.
-debug
Produce additional information about the loading/validation process
-recurse
Look in subfolders when -ig refers to a folder
-locale
Specifies the locale/language of the validation result messages (eg.: de-DE
-sct
Specify the edition of SNOMED CT to use. Valid Choices:
intl | us | uk | au | nl | ca | se | dk | es
tx.fhir.org only supports a subset. To add to this list or tx.fhir.org
ask on https://chat.fhir.org/#narrow/stream/179202-terminology
-native: use schema for validation as well
* XML: w3c schema+schematron
* JSON: json.schema
* RDF: SHEX
Default: false
-language: [lang]
The language to use when validating coding displays - same value as for xml:lang
Not used if the resource specifies language
Default: no specified language
-strictExtensions: If present, treat extensions not defined within the specified FHIR version and any
referenced implementation guides or profiles as errors. (Default is to only raise information messages.)
-hintAboutNonMustSupport: If present, raise hints if the instance contains data elements that are not
marked as mustSupport=true. Useful to identify elements included that may be ignored by recipients
-assumeValidRestReferences: If present, assume that URLs that reference resources follow the RESTful URI pattern
and it is safe to infer the type from the URL
-security-checks: If present, check that string content doesn't include any html-like tags that might create
problems downstream (though all external input must always be santized by escaping for either html or sql)
The validator also supports the param -proxy=[address]:[port] for if you use a proxy
Parameters can appear in any order
Alternatively, you can use the validator to execute a transformation as described by a structure map.
To do this, you must provide some additional parameters:
-transform [map]
* [map] the URI of the map that the transform starts with
Any other dependency maps have to be loaded through an -ig reference
-transform uses the parameters -defn, -txserver, -ig (at least one with the map files), and -output
Alternatively, you can use the validator to generate narrative for a resource.
To do this, you must provide a specific parameter:
-narrative
-narrative requires the parameters -defn, -txserver, -source, and -output. ig and profile may be used
Alternatively, you can use the validator to convert a resource or logical model.
To do this, you must provide a specific parameter:
-convert
-convert requires the parameters -source and -output. ig may be used to provide a logical model
Alternatively, you can use the validator to evaluate a FHIRPath expression on a resource or logical model.
To do this, you must provide a specific parameter:
-fhirpath [FHIRPath]
* [FHIRPath] the FHIRPath expression to evaluate
-fhirpath requires the parameters -source. ig may be used to provide a logical model
Finally, you can use the validator to generate a snapshot for a profile.
To do this, you must provide a specific parameter:
-snapshot
-snapshot requires the parameters -defn, -txserver, -source, and -output. ig may be used to provide necessary base profiles

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1,72 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 58 58" style="enable-background:new 0 0 58 58;" xml:space="preserve">
<g>
<path d="M33.655,45.988c-0.232-0.31-0.497-0.533-0.793-0.67s-0.608-0.205-0.937-0.205c-0.337,0-0.658,0.063-0.964,0.191
s-0.579,0.344-0.82,0.649s-0.431,0.699-0.567,1.183c-0.137,0.483-0.21,1.075-0.219,1.777c0.009,0.684,0.08,1.267,0.212,1.75
s0.314,0.877,0.547,1.183s0.497,0.528,0.793,0.67s0.608,0.212,0.937,0.212c0.337,0,0.658-0.066,0.964-0.198s0.579-0.349,0.82-0.649
s0.431-0.695,0.567-1.183s0.21-1.082,0.219-1.784c-0.009-0.684-0.08-1.265-0.212-1.743S33.888,46.298,33.655,45.988z"/>
<path d="M51.5,39V13.978c0-0.766-0.092-1.333-0.55-1.792L39.313,0.55C38.964,0.201,38.48,0,37.985,0H8.963
C7.777,0,6.5,0.916,6.5,2.926V39H51.5z M29.5,33c0,0.552-0.447,1-1,1s-1-0.448-1-1v-3c0-0.552,0.447-1,1-1s1,0.448,1,1V33z
M37.5,3.391c0-0.458,0.553-0.687,0.877-0.363l10.095,10.095C48.796,13.447,48.567,14,48.109,14H37.5V3.391z M36.5,24v-4
c0-0.551-0.448-1-1-1c-0.553,0-1-0.448-1-1s0.447-1,1-1c1.654,0,3,1.346,3,3v4c0,1.103,0.897,2,2,2c0.553,0,1,0.448,1,1
s-0.447,1-1,1c-1.103,0-2,0.897-2,2v4c0,1.654-1.346,3-3,3c-0.553,0-1-0.448-1-1s0.447-1,1-1c0.552,0,1-0.449,1-1v-4
c0-1.2,0.542-2.266,1.382-3C37.042,26.266,36.5,25.2,36.5,24z M28.5,22c0.828,0,1.5,0.672,1.5,1.5S29.328,25,28.5,25
c-0.828,0-1.5-0.672-1.5-1.5S27.672,22,28.5,22z M16.5,26c1.103,0,2-0.897,2-2v-4c0-1.654,1.346-3,3-3c0.553,0,1,0.448,1,1
s-0.447,1-1,1c-0.552,0-1,0.449-1,1v4c0,1.2-0.542,2.266-1.382,3c0.84,0.734,1.382,1.8,1.382,3v4c0,0.551,0.448,1,1,1
c0.553,0,1,0.448,1,1s-0.447,1-1,1c-1.654,0-3-1.346-3-3v-4c0-1.103-0.897-2-2-2c-0.553,0-1-0.448-1-1S15.947,26,16.5,26z"/>
<path d="M6.5,41v15c0,1.009,1.22,2,2.463,2h40.074c1.243,0,2.463-0.991,2.463-2V41H6.5z M18.021,51.566
c0,0.474-0.087,0.873-0.26,1.196s-0.405,0.583-0.697,0.779s-0.627,0.333-1.005,0.41c-0.378,0.077-0.768,0.116-1.169,0.116
c-0.2,0-0.436-0.021-0.704-0.062s-0.547-0.104-0.834-0.191s-0.563-0.185-0.827-0.294s-0.487-0.232-0.67-0.369l0.697-1.107
c0.091,0.063,0.221,0.13,0.39,0.198s0.354,0.132,0.554,0.191s0.41,0.111,0.629,0.157s0.424,0.068,0.615,0.068
c0.483,0,0.868-0.094,1.155-0.28s0.439-0.504,0.458-0.95v-7.711h1.668V51.566z M25.958,52.298c-0.15,0.342-0.362,0.643-0.636,0.902
s-0.61,0.467-1.012,0.622s-0.856,0.232-1.367,0.232c-0.219,0-0.444-0.012-0.677-0.034s-0.467-0.062-0.704-0.116
c-0.237-0.055-0.463-0.13-0.677-0.226s-0.398-0.212-0.554-0.349l0.287-1.176c0.128,0.073,0.289,0.144,0.485,0.212
s0.398,0.132,0.608,0.191s0.419,0.107,0.629,0.144s0.405,0.055,0.588,0.055c0.556,0,0.982-0.13,1.278-0.39s0.444-0.645,0.444-1.155
c0-0.31-0.104-0.574-0.314-0.793s-0.472-0.417-0.786-0.595s-0.654-0.355-1.019-0.533s-0.706-0.388-1.025-0.629
s-0.583-0.526-0.793-0.854s-0.314-0.738-0.314-1.23c0-0.446,0.082-0.843,0.246-1.189s0.385-0.641,0.663-0.882
s0.602-0.426,0.971-0.554s0.759-0.191,1.169-0.191c0.419,0,0.843,0.039,1.271,0.116s0.774,0.203,1.039,0.376
c-0.055,0.118-0.118,0.248-0.191,0.39s-0.142,0.273-0.205,0.396s-0.118,0.226-0.164,0.308s-0.073,0.128-0.082,0.137
c-0.055-0.027-0.116-0.063-0.185-0.109s-0.166-0.091-0.294-0.137s-0.296-0.077-0.506-0.096s-0.479-0.014-0.807,0.014
c-0.183,0.019-0.355,0.07-0.52,0.157s-0.31,0.193-0.438,0.321s-0.228,0.271-0.301,0.431s-0.109,0.313-0.109,0.458
c0,0.364,0.104,0.658,0.314,0.882s0.47,0.419,0.779,0.588s0.647,0.333,1.012,0.492s0.704,0.354,1.019,0.581
s0.576,0.513,0.786,0.854s0.314,0.781,0.314,1.319C26.184,51.603,26.108,51.956,25.958,52.298z M35.761,51.156
c-0.214,0.647-0.511,1.185-0.889,1.613s-0.82,0.752-1.326,0.971s-1.06,0.328-1.661,0.328s-1.155-0.109-1.661-0.328
s-0.948-0.542-1.326-0.971s-0.675-0.966-0.889-1.613s-0.321-1.395-0.321-2.242s0.107-1.593,0.321-2.235s0.511-1.178,0.889-1.606
s0.82-0.754,1.326-0.978s1.06-0.335,1.661-0.335s1.155,0.111,1.661,0.335s0.948,0.549,1.326,0.978s0.675,0.964,0.889,1.606
s0.321,1.388,0.321,2.235S35.975,50.509,35.761,51.156z M45.68,54h-1.668l-3.951-6.945V54h-1.668V43.924h1.668l3.951,6.945v-6.945
h1.668V54z"/>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -1,51 +0,0 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 58 58" style="enable-background:new 0 0 58 58;" xml:space="preserve">
<g>
<path d="M51.5,39V13.978c0-0.766-0.092-1.333-0.55-1.792L39.313,0.55C38.964,0.201,38.48,0,37.985,0H8.963
C7.777,0,6.5,0.916,6.5,2.926V39H51.5z M37.5,3.391c0-0.458,0.553-0.687,0.877-0.363l10.095,10.095
C48.796,13.447,48.567,14,48.109,14H37.5V3.391z M33.793,18.707c-0.391-0.391-0.391-1.023,0-1.414s1.023-0.391,1.414,0l6,6
c0.391,0.391,0.391,1.023,0,1.414l-6,6C35.012,30.902,34.756,31,34.5,31s-0.512-0.098-0.707-0.293
c-0.391-0.391-0.391-1.023,0-1.414L39.086,24L33.793,18.707z M24.557,31.667l6-17c0.185-0.521,0.753-0.795,1.276-0.61
c0.521,0.184,0.794,0.755,0.61,1.276l-6,17C26.298,32.744,25.912,33,25.5,33c-0.11,0-0.223-0.019-0.333-0.058
C24.646,32.759,24.373,32.188,24.557,31.667z M15.793,23.293l6-6c0.391-0.391,1.023-0.391,1.414,0s0.391,1.023,0,1.414L17.914,24
l5.293,5.293c0.391,0.391,0.391,1.023,0,1.414C23.012,30.902,22.756,31,22.5,31s-0.512-0.098-0.707-0.293l-6-6
C15.402,24.316,15.402,23.684,15.793,23.293z"/>
<path d="M6.5,41v15c0,1.009,1.22,2,2.463,2h40.074c1.243,0,2.463-0.991,2.463-2V41H6.5z M22.936,54h-1.9l-1.6-3.801h-0.137
L17.576,54h-1.9l2.557-4.895l-2.721-5.182h1.873l1.777,4.102h0.137l1.928-4.102H23.1l-2.721,5.182L22.936,54z M34.666,54h-1.668
v-6.932l-2.256,5.605h-1.449l-2.27-5.605V54h-1.668V43.924h1.668l2.994,6.891l2.98-6.891h1.668V54z M43.498,54h-6.303V43.924h1.668
v8.832h4.635V54z"/>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -1,56 +0,0 @@
<!--aside id="sidebar">
<div class="">
<label>Validation Options</label>
<ul>
<li><input type="checkbox" id="doNative">doNative</li>
<li><input type="checkbox" id="anyExtensionAllowed">anyExtensionAllowed</li>
<li><input type="checkbox" id="hintAboutNonMustSupport">hintAboutNonMustSupport</li>
<li><input type="checkbox" id="recursive">recursive</li>
<li><input type="checkbox" id="doDebug">doDebug</li>
<li><input type="checkbox" id="assumeValidRestReferences">assumeValidRestReferences</li>
<li><input type="checkbox" name="canDoNative" id="canDoNative">canDoNative</li>
<li>
<label>Map</label>
<input type="text" name="map" placeholder="enter map">
</li>
<li>
<label>Output</label>
<input type="text" name="output" placeholder="enter output">
</li>
<li>
<label>txServer</label>
<input type="text" name="txServer" placeholder="enter txServer">
</li>
<li>
<label>sv</label>
<input type="text" name="sv" placeholder="enter sv">
</li>
<li>
<label>txLog</label>
<input type="text" name="txLog" placeholder="enter txLog">
</li>
<li>
<label>mapLog</label>
<input type="text" name="mapLog" placeholder="enter mapLog">
</li>
<li>
<label>lang</label>
<input type="text" name="lang" placeholder="enter lang">
</li>
<li>
<label>fhirpath</label>
<input type="text" name="fhirpath" placeholder="enter fhirpath">
</li>
<li>
<label>snomedCT</label>
<input type="text" name="snomedCT" placeholder="enter snomedCT">
</li>
<li>
<label>targetVer</label>
<input type="text" name="targetVer" placeholder="enter targetVer">
</li>
</ul>
<input id='test_button' class="btn" type="submit" value="Submit">
</div>
</aside-->

View File

@ -1,17 +0,0 @@
export const FhirFormat = {
XML: {
extension:'xml'
},
JSON: {
extension:'json'
},
TURTLE: {
extension:'ttl'
},
TEXT: {
extension:'txt'
},
VBAR: {
extension:'hl7'
},
}

View File

@ -1,14 +0,0 @@
export const IssueSeverity = {
FATAL: {
code: 'Fatal'
},
ERROR: {
code: 'Error'
},
WARNING: {
code: 'Warning'
},
INFORMATION: {
code: 'Information'
}
}

View File

@ -1,30 +0,0 @@
export const Locale = {
ENGLISH: {
code: 'en',
value: 'English'
},
FRENCH: {
code: 'fr',
value: 'French'
},
GERMAN: {
code: 'de',
value: 'German'
},
ITALIAN: {
code: 'it',
value: 'Italian'
},
JAPANESE: {
code: 'ja',
value: 'Japanese'
},
KOREAN: {
code: 'ko',
value: 'Korean'
},
CHINESE: {
code: 'zh',
value: 'Chinese'
}
}

View File

@ -1,38 +0,0 @@
export const SnomedVersion = {
INTL: {
value: "intl",
code: "900000000000207008"
},
US: {
value: "us",
code: "731000124108"
},
UK: {
value: "uk",
code: "999000041000000102"
},
AU: {
value: "au",
code: "32506021000036107"
},
CA: {
value: "ca",
code: "20611000087101"
},
NL: {
value: "nl",
code: "11000146104"
},
SE: {
value: "se",
code: "45991000052106"
},
ES: {
value: "es",
code: "449081005"
},
DK: {
value: "dk",
code: "554471000005108"
}
}

View File

@ -1,99 +0,0 @@
<html lang="en"><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="Mark Iantorno">
<meta name="generator" content="Jekyll v3.8.6">
<title>FHIR HL7 Resrouce Validator GUI</title>
<!-- Bootstrap core CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<link rel="canonical" href="https://getbootstrap.com/docs/4.4/examples/offcanvas/">
<!-- Favicons -->
<meta name="theme-color" content="#563d7c">
<style>
.bd-placeholder-img {
font-size: 1.125rem;
text-anchor: middle;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
@media (min-width: 768px) {
.bd-placeholder-img-lg {
font-size: 3.5rem;
}
}
</style>
<!-- Custom styles for this template -->
<link href="style.css" rel="stylesheet">
</head>
<body class="bg-light">
<main role="main" class="container">
<div class="d-flex align-items-center p-3 my-3 text-white-50 bg-secondary rounded shadow-sm">
<img class="mr-3" src="./assets/fhir-logo-www.png" alt="" height="48">
<div class="lh-100">
<h6 class="mb-0 text-white lh-100">FHIR Core Validator</h6>
<small class="text-white">Experimental</small>
</div>
</div>
<div class="my-3 p-3 bg-white rounded shadow-sm">
<div class="d-flex border-bottom border-gray justify-content-between align-items-center w-100">
<h6 class="pb-2 mb-0">Files to Validate</h6>
<button id="validate_button" class="btn btn-secondary mb-1">Validate</button>
</div>
<div class="accordion" id="accordionExample">
<ul id="file_entry_file_list" class="list-group border">
</ul>
</div>
<div class="bd-callout bd-callout-info">
<small class="d-block text-right mt-3">
<input type="file" style="display:none;" id="files" name="files[]" multiple="" >
<button type="button" class="btn btn-secondary" onclick="document.getElementById('files').click()">Add Files</button>
</small>
</div>
<template id="file_entry_template">
<li class="list-unstyled">
<div class="card">
<div class="card-header" id="headingOne">
<div class="d-flex">
<div class="d-flex align-items-center">
<img id="file_entry_type_icon" class="bd-placeholder-img mr-2 rounded" src="./assets/json-svgrepo-com.svg" width="32" height="32" preserveaspectratio="xMidYMid slice">
<button id="file_entry_name_field" class="btn btn-link" type="button" data-toggle="collapse" data-target="#file_entry_collapse_section" aria-expanded="true" aria-controls="file_entry_collapse_section">
Collapsible Group Item #1
</button>
</div>
<div class="ml-auto d-flex">
<svg id="file_entry_delete_button" class="delete_button align-self-center" height="24" viewBox="0 0 24 24" width="24">
<path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zm2.46-7.12l1.41-1.41L12 12.59l2.12-2.12 1.41 1.41L13.41 14l2.12 2.12-1.41 1.41L12 15.41l-2.12 2.12-1.41-1.41L10.59 14l-2.13-2.12zM15.5 4l-1-1h-5l-1 1H5v2h14V4z"></path>
</svg>
</div>
</div>
</div>
<div id="file_entry_collapse_section" class="collapse" aria-labelledby="headingOne" data-parent="#accordionExample">
<div class="card-body">
<ul id="file_entry_outcome_list" class="list-group">
</ul>
</div>
</div>
</div>
</li>
</template>
</div>
</main>
<script type="module" src="./main.js"></script>
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
</body></html>

View File

@ -1,206 +0,0 @@
import {CliContext} from './model/CliContext.js';
import {ValidationRequest} from './model/ValidationRequest.js';
import {FileInfo} from './model/FileInfo.js';
import {FhirFormat} from './enums/FhirFormat.js';
import {IssueSeverity} from './enums/IssueSeverity.js';
/*
<Constants>
*/
// Icon Constants
const jsonIcon = './assets/json-svgrepo-com.svg';
const xmlIcon = './assets/xml-svgrepo-com.svg';
// HTML classes
const CLASS_LIST_ITEM_PLAIN = "list-group-item";
const CLASS_LIST_ITEM_FATAL = "list-group-item list-group-item-dark";
const CLASS_LIST_ITEM_ERROR = "list-group-item list-group-item-danger";
const CLASS_LIST_ITEM_WARNING = "list-group-item list-group-item-warning";
const CLASS_LIST_ITEM_INFORMATION = "list-group-item list-group-item-info";
// HTML IDs
const ID_FILE_ENTRY_TEMPLATE = '#file_entry_template';
const ID_FILE_ENTRY_NAME = 'file_entry_name_field';
const ID_FILE_ENTRY_ICON = 'file_entry_type_icon';
const ID_FILE_ENTRY_DELETE_BUTTON = 'file_entry_delete_button';
const ID_FILE_ENTRY_FILE_LIST = 'file_entry_file_list';
const ID_FILE_ENTRY_OUTCOME_LIST = 'file_entry_outcome_list';
const ID_FILE_ENTRY_COLLAPSE_SECTION = 'file_entry_collapse_section';
/*
</Constants>
*/
// Data Fields
const cli = new CliContext();
const filesToValidate = [];
document.getElementById('validate_button').addEventListener("click", validateCurrentFiles);
document.getElementById('files').addEventListener('change', handleFileSelect, false);
// File reading
function handleFileSelect(evt) {
var files = evt.target.files;
var output = [];
for (var i = 0, f; f = files[i]; i++) {
generateFileEntry(f);
// Check for proper file type here
console.log(f.type);
}
}
function generateFileEntry(file) {
var fr = new FileReader();
fr.onload = function(e) {
// TODO there may be timing issues here
filesToValidate.push(new FileInfo(file.name, e.target.result, file.type));
document.getElementById(ID_FILE_ENTRY_FILE_LIST).appendChild(generateNewFileListItemFromTemplate(file, filesToValidate.length - 1));
};
fr.readAsText(file);
}
// File List Template Generation
function generateNewFileListItemFromTemplate(file, index) {
var template = document.querySelector(ID_FILE_ENTRY_TEMPLATE);
var clone = template.content.cloneNode(true);
// Add file name
clone.getElementById(ID_FILE_ENTRY_NAME).textContent = file.name;
// Add appropriate icon for filetype
if (file.type.includes(FhirFormat.JSON.extension)) {
clone.getElementById(ID_FILE_ENTRY_ICON).src = jsonIcon;
} else if (file.type.includes(FhirFormat.XML.extension)) {
clone.getElementById(ID_FILE_ENTRY_ICON).src = xmlIcon;
}
clone.getElementById(ID_FILE_ENTRY_COLLAPSE_SECTION).setAttribute("id", (ID_FILE_ENTRY_COLLAPSE_SECTION + index));
clone.getElementById(ID_FILE_ENTRY_NAME).setAttribute("aria-controls", (ID_FILE_ENTRY_COLLAPSE_SECTION + index));
clone.getElementById(ID_FILE_ENTRY_NAME).setAttribute("data-target", ('#' + ID_FILE_ENTRY_COLLAPSE_SECTION + index));
// Add delete listener
clone.getElementById(ID_FILE_ENTRY_DELETE_BUTTON).addEventListener("click", handleDeleteOnFileList);
return clone;
}
function addIssueToFileEntryList(index, severity, details) {
var ul = document.getElementById(ID_FILE_ENTRY_FILE_LIST);
var listItems = ul.children;
var fileEntry = listItems[index];
console.log(fileEntry);
var listOfIssues = fileEntry.querySelector('#' + ID_FILE_ENTRY_OUTCOME_LIST);
var issueItem = createIssueListItem(severity, details);
listOfIssues.appendChild(issueItem);
}
function createIssueListItem(severity, details) {
var newIssue = document.createElement('li');
switch(severity) {
case IssueSeverity.FATAL.code:
newIssue.setAttribute("class", CLASS_LIST_ITEM_FATAL);
break;
case IssueSeverity.ERROR.code:
newIssue.setAttribute("class", CLASS_LIST_ITEM_ERROR);
break;
case IssueSeverity.WARNING.code:
newIssue.setAttribute("class", CLASS_LIST_ITEM_WARNING);
break;
case IssueSeverity.INFORMATION.code:
newIssue.setAttribute("class", CLASS_LIST_ITEM_INFORMATION);
break;
default:
console.error('Passed in bad severity: ' + severity);
}
newIssue.innerHTML = details;
return newIssue;
}
function handleDeleteOnFileList(e) {
var li = e.target.closest('li');
var nodes = Array.from( li.closest('ul').children );
var index = nodes.indexOf( li );
nodes[index].remove();
filesToValidate.splice((index - 1), 1);
console.log('Index -> ' + index);
console.log(filesToValidate);
}
// Validation
function validateCurrentFiles() {
sendFilesToValidate(filesToValidate);
}
function sendFilesToValidate(arrayOfFileInfo) {
var req = new ValidationRequest();
req.filesToValidate = arrayOfFileInfo;
var xhr = new XMLHttpRequest();
xhr.open("POST", 'http://localhost:8080/' + 'validate', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(req));
xhr.onload = function () {
const response = '{"outcomes": [{"fileInfo": {"fileName": "account-example.canonical.json", "fileType": "JSON"}, "issues": [{"severity": "Error", "details": "\"null\""}, {"severity": "Error", "details": "Profile http://hl7.org/fhir/StructureDefinition/Account, Element: minimum required = 1, but only found 0"}]}, {"fileInfo": {"fileName": "account-example(example).xml", "fileType": "XML"}, "issues": []}]}';
var test = xhr.responseText;
processValidationResponse(JSON.parse(JSON.parse(xhr.responseText)));
};
}
function processValidationResponse(validationResponse) {
console.log(validationResponse);
console.log(validationResponse.length);
console.log(validationResponse.outcomes);
console.log(validationResponse.outcomes.length);
for (var i = 0; i < validationResponse.outcomes.length; i++) {
console.log(validationResponse.outcomes[i]);
var fileInfo = validationResponse.outcomes[i].fileInfo;
var issues = validationResponse.outcomes[i].issues;
issues.forEach(issue => {
console.log(issue);
addIssueToFileEntryList(i, issue.severity, issue.details);
});
}
}
// window.onload = function loadCliContext() {
// var xhr = new XMLHttpRequest();
// xhr.open("GET", 'http://localhost:8080/currentContext');
// xhr.send();
// xhr.onreadystatechange = function() {
// if (this.readyState == 4 && this.status == 200) {
// console.log(xhr.responseText);
// }
// }
// }
// /*
// Escape JSON
// */
// var escapeJSON = exports.escapeJSON = function(json) {
// var escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
// var meta = { // table of character substitutions
// '\b': '\\b',
// '\t': '\\t',
// '\n': '\\n',
// '\f': '\\f',
// '\r': '\\r',
// '"' : '\\"',
// '\\': '\\\\'
// };
//
// escapable.lastIndex = 0;
// return escapable.test(json) ? '"' + json.replace(escapable, function (a) {
// var c = meta[a];
// return (typeof c === 'string') ? c
// : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
// }) + '"' : '"' + json + '"';
//
// };

View File

@ -1,34 +0,0 @@
import {SnomedVersion} from '../enums/SnomedVersion.js';
import {Locale} from '../enums/Locale.js';
export class CliContext {
constructor(){
this.doNative = false;
this.anyExtensionsAllowed = true;
this.hintAboutNonMustSupport = false;
this.recursive = false;
this.doDebug = false;
this.assumeValidRestReferences = false;
this.canDoNative = false;
this.map = null;
this.output = null;
this.txServer = "http://tx.fhir.org";
this.sv = "current";
this.txLog = null;
this.mapLog = null;
this.lang = null;
this.fhirpath = null;
this.snomedCT = SnomedVersion.ES.value;
this.targetVer = null;
this.igs = [];
this.questionnaires = [];
this.profiles = [];
this.sources = [];
this.locale = Locale.ENGLISH.value;
this.locations = new Map();
}
}

View File

@ -1,13 +0,0 @@
import {FhirFormat} from '../enums/FhirFormat.js';
export class FileInfo {
constructor(fileName, fileContent, type){
this.fileName = fileName;
this.fileContent = fileContent;
if (type.includes('json')) {
this.fileType = FhirFormat.JSON.extension;
} else if (type.includes('xml')) {
this.fileType = FhirFormat.XML.extension;
}
}
}

View File

@ -1,6 +0,0 @@
export class ValidationIssue {
constructor(){
this.severity = "";
this.details = "";
}
}

View File

@ -1,8 +0,0 @@
import {FileInfo} from './FileInfo.js';
export class ValidationOutcome {
constructor(){
this.fileInfo = null;
this.issues = [];
}
}

View File

@ -1,8 +0,0 @@
import {CliContext} from './CliContext.js';
export class ValidationRequest {
constructor(){
this.cliContext = new CliContext();
this.filesToValidate = [];
}
}

View File

@ -1,7 +0,0 @@
import {ValidationOutcome} from './ValidationOutcome.js';
export class ValidationResponse {
constructor() {
this.outcomes = [];
}
}

View File

@ -1,94 +0,0 @@
/* */
.container{
width:80%;
margin:auto;
overflow: hidden;
}
#main{
float: left;
width: 70%;
}
#sidebar{
float: right;
width: 30%;
}
html,
body {
overflow-x: hidden; /* Prevent scroll on narrow devices */
}
body {
padding-top: 56px;
}
@media (max-width: 991.98px) {
.offcanvas-collapse {
position: fixed;
top: 56px; /* Height of navbar */
bottom: 0;
left: 100%;
width: 100%;
padding-right: 1rem;
padding-left: 1rem;
overflow-y: auto;
visibility: hidden;
background-color: #343a40;
transition: visibility .3s ease-in-out, -webkit-transform .3s ease-in-out;
transition: transform .3s ease-in-out, visibility .3s ease-in-out;
transition: transform .3s ease-in-out, visibility .3s ease-in-out, -webkit-transform .3s ease-in-out;
}
.offcanvas-collapse.open {
visibility: visible;
-webkit-transform: translateX(-100%);
transform: translateX(-100%);
}
}
.nav-scroller {
position: relative;
z-index: 2;
height: 2.75rem;
overflow-y: hidden;
}
.nav-scroller .nav {
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: nowrap;
flex-wrap: nowrap;
padding-bottom: 1rem;
margin-top: -1px;
overflow-x: auto;
color: rgba(255, 255, 255, .75);
text-align: center;
white-space: nowrap;
-webkit-overflow-scrolling: touch;
}
.nav-underline .nav-link {
padding-top: .75rem;
padding-bottom: .75rem;
font-size: .875rem;
color: #6c757d;
}
.nav-underline .nav-link:hover {
color: #007bff;
}
.nav-underline .active {
font-weight: 500;
color: #343a40;
}
.text-white-50 { color: rgba(255, 255, 255, .5); }
.bg-purple { background-color: #6f42c1; }
.lh-100 { line-height: 1; }
.lh-125 { line-height: 1.25; }
.lh-150 { line-height: 1.5; }

View File

@ -1,37 +0,0 @@
package org.hl7.fhir.validation.cli;
import java.io.IOException;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.hl7.fhir.validation.cli.model.CliContext;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
public abstract class BaseRestTest {
protected final String JSON_MIME_TYPE = "application/json";
@BeforeAll
public static void startServer() {
ValidatorGui.start(new CliContext(), null, false);
}
@AfterAll
public static void stopServer() {
ValidatorGui.stop();
}
public static <T> T retrieveResourceFromResponse(HttpResponse response, Class<T> clazz)
throws IOException {
String jsonFromResponse = EntityUtils.toString(response.getEntity());
ObjectMapper mapper = new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return mapper.readValue(jsonFromResponse, clazz);
}
}

View File

@ -1,35 +0,0 @@
package org.hl7.fhir.validation.cli;
import java.io.IOException;
import org.hl7.fhir.validation.cli.model.CliContext;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import io.github.bonigarcia.wdm.WebDriverManager;
class ValidatorGuiTest {
private static final String DEF_TX = "http://tx.fhir.org";
private final String HTML_TITLE_TAG = "<title>FHIR HL7 Resrouce Validator GUI</title>";
@Test
@DisplayName("Page boots correctly, and displays index.html")
public void UI_contains_correct_heading() throws IOException {
ValidatorGui.start(new CliContext(), null, false);
WebDriverManager.chromedriver().setup();
ChromeOptions options = new ChromeOptions();
options.addArguments("--headless");
options.addArguments("--disable-gpu");
WebDriver driver = new ChromeDriver(options);
driver.get("http://localhost:" + ValidatorGui.getPort() + "/home");
Assertions.assertTrue(driver.getPageSource().contains(HTML_TITLE_TAG));
driver.quit();
ValidatorGui.stop();
}
}

View File

@ -1,48 +0,0 @@
package org.hl7.fhir.validation.cli.controller;
import java.io.IOException;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.HttpClientBuilder;
import org.hl7.fhir.validation.cli.BaseRestTest;
import org.hl7.fhir.validation.cli.ValidatorGui;
import org.hl7.fhir.validation.cli.model.CliContext;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
class HttpGetContextTest extends BaseRestTest {
private final String GET_CONTEXT_URL = "http://localhost:" + ValidatorGui.getPort() + "/context";
@Test
@DisplayName("Testing status code on get context endpoint.")
public void testStatus() throws IOException {
HttpUriRequest request = new HttpGet(GET_CONTEXT_URL);
HttpResponse httpResponse = HttpClientBuilder.create().build().execute(request);
Assertions.assertEquals(httpResponse.getStatusLine().getStatusCode(), HttpStatus.SC_OK);
}
@Test
@DisplayName("Testing media type on get context endpoint.")
public void testMediaType() throws IOException {
HttpUriRequest request = new HttpGet(GET_CONTEXT_URL);
HttpResponse httpResponse = HttpClientBuilder.create().build().execute(request);
String mimeType = ContentType.getOrDefault(httpResponse.getEntity()).getMimeType();
Assertions.assertEquals(JSON_MIME_TYPE, mimeType );
}
@Test
@DisplayName("Testing status code on get context endpoint.")
public void testJSONPayload() throws IOException {
HttpUriRequest request = new HttpGet(GET_CONTEXT_URL);
HttpResponse httpResponse = HttpClientBuilder.create().build().execute(request);
CliContext resource = retrieveResourceFromResponse(httpResponse, CliContext.class);
Assertions.assertEquals(new CliContext(), resource);
}
}

View File

@ -1,26 +0,0 @@
package org.hl7.fhir.validation.cli.controller;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import io.javalin.http.Context;
class HttpPutContextTest {
public CliContextController myCliContextController;
public HttpPutContextTest() {
this.myCliContextController = new CliContextController(null);
}
@Disabled
@Test
void handleSetCurrentCliContext() {
Context context = mock(Context.class);
this.myCliContextController.handleSetCurrentCliContext(context);
verify(context).status(200);
}
}

View File

@ -2,7 +2,7 @@ package org.hl7.fhir.validation.tests;
import org.hl7.fhir.r4.context.SimpleWorkerContext; import org.hl7.fhir.r4.context.SimpleWorkerContext;
import org.hl7.fhir.r5.test.utils.TestingUtilities; import org.hl7.fhir.r5.test.utils.TestingUtilities;
import org.hl7.fhir.validation.Validator; import org.hl7.fhir.validation.ValidatorCli;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -13,7 +13,7 @@ public class CDAValidationTest {
@Test @Test
public void test() throws Exception { public void test() throws Exception {
Validator.main(new String[] {TestingUtilities.loadTestResource("ccda.xml"), "-ig", "hl7.fhir.cda"}); ValidatorCli.main(new String[] {TestingUtilities.loadTestResource("ccda.xml"), "-ig", "hl7.fhir.cda"});
} }
} }

View File

@ -4,7 +4,7 @@ import java.io.File;
import org.hl7.fhir.r4.test.utils.TestingUtilities; import org.hl7.fhir.r4.test.utils.TestingUtilities;
import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.validation.Validator; import org.hl7.fhir.validation.ValidatorCli;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -18,7 +18,7 @@ public class TransformationTests {
String output = Utilities.path("[tmp]", "cda-bundle.txt"); String output = Utilities.path("[tmp]", "cda-bundle.txt");
String log = Utilities.path("[tmp]", "transform-log.txt"); String log = Utilities.path("[tmp]", "transform-log.txt");
Validator.main(new String[] {input, "-transform", "http://hl7.org/fhir/cda/mapping/ccdaDocumentToFhir", "-ig", "hl7.fhir.cda", "-ig", mappings, "-output", output, "-log", log}); ValidatorCli.main(new String[] {input, "-transform", "http://hl7.org/fhir/cda/mapping/ccdaDocumentToFhir", "-ig", "hl7.fhir.cda", "-ig", mappings, "-output", output, "-log", log});
checkFile(output); checkFile(output);
checkFile(log); checkFile(log);
} }