diff --git a/hapi-fhir-cli/pom.xml b/hapi-fhir-cli/pom.xml
index e9006179fb1..c823c82bbe5 100644
--- a/hapi-fhir-cli/pom.xml
+++ b/hapi-fhir-cli/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 1.2-SNAPSHOT
+ 1.2
../pom.xml
@@ -22,33 +22,33 @@
ca.uhn.hapi.fhir
hapi-fhir-base
- 1.2-SNAPSHOT
+ 1.2
ca.uhn.hapi.fhir
hapi-fhir-jpaserver-example
- 1.2-SNAPSHOT
+ 1.2
war
ca.uhn.hapi.fhir
hapi-fhir-structures-dstu
- 1.2-SNAPSHOT
+ 1.2
ca.uhn.hapi.fhir
hapi-fhir-structures-dstu2
- 1.2-SNAPSHOT
+ 1.2
ca.uhn.hapi.fhir
hapi-fhir-structures-hl7org-dstu2
- 1.2-SNAPSHOT
+ 1.2
ca.uhn.hapi.fhir
- hapi-fhir-validation-resources
- 1.2-SNAPSHOT
+ hapi-fhir-validation-resources-dstu2
+ 1.2
@@ -143,7 +143,7 @@
ca.uhn.hapi.fhir
hapi-fhir-jpaserver-example
- 1.2-SNAPSHOT
+ 1.2
war
true
target/classes
diff --git a/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/App.java b/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/App.java
index d215b269445..a514fe3e854 100644
--- a/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/App.java
+++ b/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/App.java
@@ -28,10 +28,13 @@ public class App {
private static List ourCommands;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(App.class);
+ public static final String LINESEP = System.getProperty("line.separator");
+
static {
ourCommands = new ArrayList();
ourCommands.add(new RunServerCommand());
ourCommands.add(new ExampleDataUploader());
+ ourCommands.add(new ValidateCommand());
Collections.sort(ourCommands);
}
@@ -79,16 +82,22 @@ public class App {
System.out.println(" hapi-fhir-cli {command} [options]");
System.out.println();
System.out.println("Commands:");
+
+ int longestCommandLength = 0;
for (BaseCommand next : ourCommands) {
- String left = " " + next.getCommandName() + " - ";
- String[] rightParts = WordUtils.wrap(next.getCommandDescription(), 80 - left.length()).split("\\n");
+ longestCommandLength = Math.max(longestCommandLength, next.getCommandName().length());
+ }
+
+ for (BaseCommand next : ourCommands) {
+ String left = " " + StringUtils.rightPad(next.getCommandName(), longestCommandLength);
+ String[] rightParts = WordUtils.wrap(next.getCommandDescription(), 80 - (left.length() + 3)).split("\\n");
for (int i = 1; i < rightParts.length; i++) {
- rightParts[i] = StringUtils.leftPad("", left.length()) + rightParts[i];
+ rightParts[i] = StringUtils.leftPad("", left.length() + 3) + rightParts[i];
}
- System.out.println(left + StringUtils.join(rightParts, '\n'));
+ System.out.println(ansi().bold().fg(Color.GREEN) + left + ansi().boldOff().fg(Color.WHITE) + " - " + ansi().bold() + StringUtils.join(rightParts, LINESEP));
}
System.out.println();
- System.out.println("See what options are available:");
+ System.out.println(ansi().boldOff().fg(Color.WHITE) + "See what options are available:");
System.out.println(" hapi-fhir-cli help {command}");
System.out.println();
}
@@ -143,12 +152,14 @@ public class App {
Options options = command.getOptions();
DefaultParser parser = new DefaultParser();
CommandLine parsedOptions;
+
+ logAppHeader();
+ loggingConfigOn();
+
try {
String[] args = Arrays.asList(theArgs).subList(1, theArgs.length).toArray(new String[theArgs.length - 1]);
parsedOptions = parser.parse(options, args, true);
- logAppHeader();
- loggingConfigOn();
// Actually execute the command
command.run(parsedOptions);
diff --git a/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/BaseCommand.java b/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/BaseCommand.java
index b110b4085a2..0ed9f849a9b 100644
--- a/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/BaseCommand.java
+++ b/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/BaseCommand.java
@@ -9,6 +9,8 @@ import ca.uhn.fhir.rest.client.IGenericClient;
public abstract class BaseCommand implements Comparable {
+ private FhirContext myFhirCtx;
+
public BaseCommand() {
super();
}
@@ -32,4 +34,11 @@ public abstract class BaseCommand implements Comparable {
public abstract void run(CommandLine theCommandLine) throws ParseException, Exception;
+ public FhirContext getFhirCtx() {
+ if (myFhirCtx == null) {
+ myFhirCtx = FhirContext.forDstu2();
+ }
+ return myFhirCtx;
+ }
+
}
\ No newline at end of file
diff --git a/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/ValidateCommand.java b/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/ValidateCommand.java
new file mode 100644
index 00000000000..7bc49ca11d4
--- /dev/null
+++ b/hapi-fhir-cli/src/main/java/ca/uhn/fhir/cli/ValidateCommand.java
@@ -0,0 +1,116 @@
+package ca.uhn.fhir.cli;
+
+import static org.apache.commons.lang3.StringUtils.defaultString;
+import static org.apache.commons.lang3.StringUtils.isBlank;
+import static org.apache.commons.lang3.StringUtils.isNotBlank;
+
+import static org.fusesource.jansi.Ansi.*;
+
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.OptionGroup;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.io.IOUtils;
+import org.fusesource.jansi.Ansi;
+
+import com.phloc.commons.io.file.FileUtils;
+
+import ca.uhn.fhir.rest.method.MethodUtil;
+import ca.uhn.fhir.rest.server.EncodingEnum;
+import ca.uhn.fhir.validation.FhirInstanceValidator;
+import ca.uhn.fhir.validation.FhirValidator;
+import ca.uhn.fhir.validation.SingleValidationMessage;
+import ca.uhn.fhir.validation.ValidationResult;
+
+public class ValidateCommand extends BaseCommand {
+
+ private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ValidateCommand.class);
+
+ @Override
+ public String getCommandDescription() {
+ return "Validate a resource using the FHIR validation tools";
+ }
+
+ @Override
+ public String getCommandName() {
+ return "validate";
+ }
+
+ @Override
+ public Options getOptions() {
+ Options retVal = new Options();
+
+ OptionGroup source = new OptionGroup();
+ source.addOption(new Option("f", "file", true, "The name of the file to validate"));
+ source.addOption(new Option("d", "data", true, "The text to validate"));
+ retVal.addOptionGroup(source);
+
+ retVal.addOption("x", "xsd", false, "Validate using Schemas");
+ retVal.addOption("s", "sch", false, "Validate using Schematrons");
+ retVal.addOption("p", "profile", false, "Validate using Profiles (StructureDefinition / ValueSet)");
+
+ retVal.addOption("e", "encoding", false, "File encoding (default is UTF-8)");
+
+ return retVal;
+ }
+
+ @Override
+ public void run(CommandLine theCommandLine) throws ParseException, Exception {
+ String fileName = theCommandLine.getOptionValue("f");
+ String contents = theCommandLine.getOptionValue("c");
+ if (isNotBlank(fileName) && isNotBlank(contents)) {
+ throw new ParseException("Can not supply both a file (-f) and data (-d)");
+ }
+ if (isBlank(fileName) && isBlank(contents)) {
+ throw new ParseException("Must supply either a file (-f) or data (-d)");
+ }
+
+ if (isNotBlank(fileName)) {
+ String encoding = theCommandLine.getOptionValue("e", "UTF-8");
+ ourLog.info("Reading file '{}' using encoding {}", fileName, encoding);
+
+ contents = IOUtils.toString(new InputStreamReader(new FileInputStream(fileName), encoding));
+ ourLog.info("Fully read - Size is {}", FileUtils.getFileSizeDisplay(contents.length()));
+ }
+
+ EncodingEnum enc = MethodUtil.detectEncodingNoDefault(defaultString(contents));
+ if (enc == null) {
+ throw new ParseException("Could not detect encoding (json/xml) of contents");
+ }
+
+ FhirValidator val = getFhirCtx().newValidator();
+ if (theCommandLine.hasOption("p")) {
+ val.registerValidatorModule(new FhirInstanceValidator());
+ }
+
+ val.setValidateAgainstStandardSchema(theCommandLine.hasOption("x"));
+ val.setValidateAgainstStandardSchematron(theCommandLine.hasOption("s"));
+
+ ValidationResult results = val.validateWithResult(contents);
+
+ StringBuilder b = new StringBuilder("Validation results:" + ansi().boldOff());
+ int count = 0;
+ for (SingleValidationMessage next : results.getMessages()) {
+ count++;
+ b.append(App.LINESEP);
+ b.append("Issue ").append(count).append(": ");
+ b.append(next.getSeverity()).append(" - ").append(next.getLocationString());
+ b.append(App.LINESEP);
+ b.append(" ").append(next.getMessage());
+ }
+
+ if (count > 0) {
+ ourLog.info(b.toString());
+ }
+
+ if (results.isSuccessful()) {
+ ourLog.info("Validation successful!");
+ } else {
+ ourLog.warn("Validation FAILED");
+ }
+ }
+}
diff --git a/hapi-fhir-dist/src/assembly/hapi-fhir-android-distribution.xml b/hapi-fhir-dist/src/assembly/hapi-fhir-android-distribution.xml
index 3253067d6c3..fb45ba4e4a7 100644
--- a/hapi-fhir-dist/src/assembly/hapi-fhir-android-distribution.xml
+++ b/hapi-fhir-dist/src/assembly/hapi-fhir-android-distribution.xml
@@ -5,7 +5,7 @@
zip
-
+ tar.bz2
false
diff --git a/hapi-fhir-dist/src/assembly/hapi-fhir-jpaserver-example.xml b/hapi-fhir-dist/src/assembly/hapi-fhir-jpaserver-example.xml
index 6268d658fad..aac691b3fd3 100644
--- a/hapi-fhir-dist/src/assembly/hapi-fhir-jpaserver-example.xml
+++ b/hapi-fhir-dist/src/assembly/hapi-fhir-jpaserver-example.xml
@@ -5,7 +5,7 @@
zip
-
+ tar.bz2
false
diff --git a/hapi-fhir-dist/src/assembly/hapi-fhir-standard-distribution.xml b/hapi-fhir-dist/src/assembly/hapi-fhir-standard-distribution.xml
index 62148b76655..65b4836e7b5 100644
--- a/hapi-fhir-dist/src/assembly/hapi-fhir-standard-distribution.xml
+++ b/hapi-fhir-dist/src/assembly/hapi-fhir-standard-distribution.xml
@@ -1,11 +1,11 @@
- hapi-fhir-standard-distribution
+ standard-distribution
zip
-
+ tar.bz2
false
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/JpaValidationSupportDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/JpaValidationSupportDstu2.java
index 33f6765ff14..7bd6d564c67 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/JpaValidationSupportDstu2.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/JpaValidationSupportDstu2.java
@@ -1,5 +1,25 @@
package ca.uhn.fhir.jpa.dao;
+/*
+ * #%L
+ * HAPI FHIR JPA Server
+ * %%
+ * Copyright (C) 2014 - 2015 University Health Network
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
import org.hl7.fhir.instance.model.ValueSet;
import org.hl7.fhir.instance.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.instance.model.ValueSet.ValueSetExpansionComponent;
diff --git a/pom.xml b/pom.xml
index 90bc5573ee4..6fae60ba666 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1287,6 +1287,7 @@
hapi-fhir-testpage-overlay
hapi-fhir-jpaserver-uhnfhirtest
hapi-fhir-android
+ hapi-fhir-cli
hapi-fhir-dist
examples