Merge branch 'master' of https://github.com/hapifhir/org.hl7.fhir.core
This commit is contained in:
commit
02b49913b0
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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)
|
||||||
|
|
|
@ -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");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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");
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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 +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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";
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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");
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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("*");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
export const EngineMode {
|
package org.hl7.fhir.validation.cli.utils;
|
||||||
|
|
||||||
|
public enum EngineMode {
|
||||||
VALIDATION,
|
VALIDATION,
|
||||||
TRANSFORM,
|
TRANSFORM,
|
||||||
NARRATIVE,
|
NARRATIVE,
|
|
@ -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");
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package org.hl7.fhir.validation.cli.utils;
|
||||||
|
|
||||||
|
public enum QuestionnaireMode {
|
||||||
|
NONE,
|
||||||
|
CHECK,
|
||||||
|
REQUIRED
|
||||||
|
}
|
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
|
@ -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;
|
||||||
|
|
|
@ -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"))) {
|
||||||
|
|
|
@ -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 |
|
@ -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 |
|
@ -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 |
|
@ -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-->
|
|
|
@ -1,17 +0,0 @@
|
||||||
export const FhirFormat = {
|
|
||||||
XML: {
|
|
||||||
extension:'xml'
|
|
||||||
},
|
|
||||||
JSON: {
|
|
||||||
extension:'json'
|
|
||||||
},
|
|
||||||
TURTLE: {
|
|
||||||
extension:'ttl'
|
|
||||||
},
|
|
||||||
TEXT: {
|
|
||||||
extension:'txt'
|
|
||||||
},
|
|
||||||
VBAR: {
|
|
||||||
extension:'hl7'
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
export const IssueSeverity = {
|
|
||||||
FATAL: {
|
|
||||||
code: 'Fatal'
|
|
||||||
},
|
|
||||||
ERROR: {
|
|
||||||
code: 'Error'
|
|
||||||
},
|
|
||||||
WARNING: {
|
|
||||||
code: 'Warning'
|
|
||||||
},
|
|
||||||
INFORMATION: {
|
|
||||||
code: 'Information'
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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'
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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>
|
|
|
@ -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 + '"';
|
|
||||||
//
|
|
||||||
// };
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
export class ValidationIssue {
|
|
||||||
constructor(){
|
|
||||||
this.severity = "";
|
|
||||||
this.details = "";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
import {FileInfo} from './FileInfo.js';
|
|
||||||
|
|
||||||
export class ValidationOutcome {
|
|
||||||
constructor(){
|
|
||||||
this.fileInfo = null;
|
|
||||||
this.issues = [];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
import {CliContext} from './CliContext.js';
|
|
||||||
|
|
||||||
export class ValidationRequest {
|
|
||||||
constructor(){
|
|
||||||
this.cliContext = new CliContext();
|
|
||||||
this.filesToValidate = [];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
import {ValidationOutcome} from './ValidationOutcome.js';
|
|
||||||
|
|
||||||
export class ValidationResponse {
|
|
||||||
constructor() {
|
|
||||||
this.outcomes = [];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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; }
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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"});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue