Refactor CLI to merge both CLI command frameworks

This commit is contained in:
James Agnew 2018-04-30 08:29:38 -04:00
parent 92dc0d42ee
commit d85efbaa5b
19 changed files with 642 additions and 392 deletions

View File

@ -47,7 +47,12 @@
<version>${project.version}</version>
<classifier>classes</classifier>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.14</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2</artifactId>
@ -232,7 +237,6 @@
<artifactItem>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-cli-jpaserver</artifactId>
<!--<version>1.5-SNAPSHOT</version>-->
<type>war</type>
<overWrite>true</overWrite>
<outputDirectory>target/classes</outputDirectory>
@ -283,35 +287,6 @@
</executions>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself. -->
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<versionRange>[2.10,)</versionRange>
<goals>
<goal>copy</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore></ignore>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

View File

@ -1,220 +1,25 @@
package ca.uhn.fhir.cli;
import static org.fusesource.jansi.Ansi.ansi;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.text.WordUtils;
import org.fusesource.jansi.Ansi;
import org.fusesource.jansi.Ansi.Color;
import org.fusesource.jansi.AnsiConsole;
import org.slf4j.LoggerFactory;
import com.phloc.commons.io.file.FileUtils;
import ca.uhn.fhir.util.VersionUtil;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;
public class App {
private static List<BaseCommand> ourCommands;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(App.class);
public class App extends BaseApp {
public static final String LINESEP = System.getProperty("line.separator");
static {
ourCommands = new ArrayList<BaseCommand>();
ourCommands.add(new RunServerCommand());
ourCommands.add(new ExampleDataUploader());
ourCommands.add(new ValidateCommand());
ourCommands.add(new ValidationDataUploader());
ourCommands.add(new WebsocketSubscribeCommand());
ourCommands.add(new UploadTerminologyCommand());
ourCommands.add(new IgPackUploader());
Collections.sort(ourCommands);
@Override
protected String provideCommandName() {
return "hapi-fhir-cli";
}
private static void logCommandUsage(BaseCommand theCommand) {
logAppHeader();
logCommandUsageNoHeader(theCommand);
@Override
protected String provideProductName() {
return "HAPI FHIR";
}
private static void logCommandUsageNoHeader(BaseCommand theCommand) {
System.out.println("Usage:");
System.out.println(" hapi-fhir-cli " + theCommand.getCommandName() + " [options]");
System.out.println();
System.out.println("Options:");
HelpFormatter fmt = new HelpFormatter();
PrintWriter pw = new PrintWriter(System.out);
fmt.printOptions(pw, 80, theCommand.getOptions(), 2, 2);
pw.flush();
pw.close();
}
private static void loggingConfigOff() {
try {
JoranConfigurator configurator = new JoranConfigurator();
configurator.setContext((LoggerContext) LoggerFactory.getILoggerFactory());
((LoggerContext) LoggerFactory.getILoggerFactory()).reset();
configurator.doConfigure(App.class.getResourceAsStream("/logback-cli-off.xml"));
} catch (JoranException e) {
e.printStackTrace();
}
}
private static void loggingConfigOn() {
try {
JoranConfigurator configurator = new JoranConfigurator();
configurator.setContext((LoggerContext) LoggerFactory.getILoggerFactory());
((LoggerContext) LoggerFactory.getILoggerFactory()).reset();
configurator.doConfigure(App.class.getResourceAsStream("/logback-cli-on.xml"));
} catch (JoranException e) {
e.printStackTrace();
}
}
private static void logUsage() {
logAppHeader();
System.out.println("Usage:");
System.out.println(" hapi-fhir-cli {command} [options]");
System.out.println();
System.out.println("Commands:");
int longestCommandLength = 0;
for (BaseCommand next : ourCommands) {
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() + 3) + rightParts[i];
}
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(ansi().boldOff().fg(Color.WHITE) + "See what options are available:");
System.out.println(" hapi-fhir-cli help {command}");
System.out.println();
}
private static void logAppHeader() {
System.out.flush();
System.out.println("------------------------------------------------------------");
System.out.println("\ud83d\udd25 " + ansi().bold() + "HAPI FHIR" + ansi().boldOff() + " " + VersionUtil.getVersion() + " - Command Line Tool");
System.out.println("------------------------------------------------------------");
System.out.println("Max configured JVM memory (Xmx): " + FileUtils.getFileSizeDisplay(Runtime.getRuntime().maxMemory(), 1));
System.out.println("Detected Java version: " + System.getProperty("java.version"));
System.out.println("------------------------------------------------------------");
@Override
protected String provideProductVersion() {
return VersionUtil.getVersion();
}
public static void main(String[] theArgs) {
loggingConfigOff();
AnsiConsole.systemInstall();
// log version while the logging is off
VersionUtil.getVersion();
if (theArgs.length == 0) {
logUsage();
return;
}
if (theArgs[0].equals("help")) {
if (theArgs.length < 2) {
logUsage();
return;
}
BaseCommand command = null;
for (BaseCommand nextCommand : ourCommands) {
if (nextCommand.getCommandName().equals(theArgs[1])) {
command = nextCommand;
break;
}
}
if (command == null) {
System.err.println("Unknown command: " + theArgs[1]);
return;
}
logCommandUsage(command);
return;
}
BaseCommand command = null;
for (BaseCommand nextCommand : ourCommands) {
if (nextCommand.getCommandName().equals(theArgs[0])) {
command = nextCommand;
break;
}
}
if (command == null) {
System.out.println("Unrecognized command: " + ansi().bold().fg(Color.RED) + theArgs[0] + ansi().boldOff().fg(Ansi.Color.WHITE));
System.out.println();
logUsage();
return;
}
Options options = command.getOptions();
DefaultParser parser = new DefaultParser();
CommandLine parsedOptions;
logAppHeader();
validateJavaVersion();
loggingConfigOn();
try {
String[] args = Arrays.asList(theArgs).subList(1, theArgs.length).toArray(new String[theArgs.length - 1]);
parsedOptions = parser.parse(options, args, true);
if (parsedOptions.getArgList().isEmpty()==false) {
throw new ParseException("Unrecognized argument: " + parsedOptions.getArgList().get(0).toString());
}
// Actually execute the command
command.run(parsedOptions);
} catch (ParseException e) {
loggingConfigOff();
System.err.println("Invalid command options for command: " + command.getCommandName());
System.err.println(" " + ansi().fg(Color.RED).bold() + e.getMessage());
System.err.println("" + ansi().fg(Color.WHITE).boldOff());
logCommandUsageNoHeader(command);
System.exit(1);
} catch (CommandFailureException e) {
ourLog.error(e.getMessage());
System.exit(1);
} catch (Exception e) {
ourLog.error("Error during execution: ", e);
System.exit(1);
}
new App().run(theArgs);
}
private static void validateJavaVersion() {
String specVersion = System.getProperty("java.specification.version");
double version = Double.parseDouble(specVersion);
if (version < 1.8) {
System.err.flush();
System.err.println("HAPI-CLI requires Java 1.8+ to run (detected " + specVersion + ")");
System.err.println("Note that the HAPI library requires only Java 1.6, but you must install");
System.err.println("a newer JVM in order to use the HAPI CLI tool.");
System.exit(1);
}
}
}

View File

@ -0,0 +1,256 @@
package ca.uhn.fhir.cli;
import ca.uhn.fhir.util.VersionUtil;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;
import com.phloc.commons.io.file.FileUtils;
import org.apache.commons.cli.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.text.WordUtils;
import org.fusesource.jansi.Ansi;
import org.fusesource.jansi.AnsiConsole;
import org.slf4j.LoggerFactory;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static org.fusesource.jansi.Ansi.ansi;
public abstract class BaseApp {
public static final String STACKFILTER_PATTERN = "%xEx{full, sun.reflect, org.junit, org.eclipse, java.lang.reflect.Method, org.springframework, org.hibernate, com.sun.proxy, org.attoparser, org.thymeleaf}";
public static final String STACKFILTER_PATTERN_PROP = "log.stackfilter.pattern";
public static final String LINESEP = System.getProperty("line.separator");
protected static final org.slf4j.Logger ourLog;
private static List<BaseCommand> ourCommands;
static {
System.setProperty(STACKFILTER_PATTERN_PROP, STACKFILTER_PATTERN);
loggingConfigOff();
// We don't use qualified names for loggers in CLI
ourLog = LoggerFactory.getLogger(App.class.getSimpleName());
}
private void logAppHeader() {
System.out.flush();
System.out.println("------------------------------------------------------------");
System.out.println("\ud83d\udd25 " + ansi().bold() + " " + provideProductName() + ansi().boldOff() + " " + provideProductVersion() + " - Command Line Tool");
System.out.println("------------------------------------------------------------");
System.out.println("Max configured JVM memory (Xmx): " + FileUtils.getFileSizeDisplay(Runtime.getRuntime().maxMemory(), 1));
System.out.println("Detected Java version: " + System.getProperty("java.version"));
System.out.println("------------------------------------------------------------");
}
private void logCommandUsage(BaseCommand theCommand) {
logAppHeader();
logCommandUsageNoHeader(theCommand);
}
private void logCommandUsageNoHeader(BaseCommand theCommand) {
System.out.println("Usage:");
System.out.println(" " + provideCommandName() + " " + theCommand.getCommandName() + " [options]");
System.out.println();
System.out.println("Options:");
// This is passed in from the launch script
String columnsString = System.getProperty("columns");
int columns;
try {
columns = Integer.parseInt(columnsString);
columns = Math.max(columns, 40);
columns = Math.min(columns, 180);
} catch (Exception e) {
columns = 80;
}
HelpFormatter fmt = new HelpFormatter();
PrintWriter pw = new PrintWriter(System.out);
fmt.printOptions(pw, columns, theCommand.getOptions(), 2, 2);
pw.flush();
pw.close();
}
private void logUsage() {
logAppHeader();
System.out.println("Usage:");
System.out.println(" " + provideCommandName() + " {command} [options]");
System.out.println();
System.out.println("Commands:");
int longestCommandLength = 0;
for (BaseCommand next : ourCommands) {
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() + 3) + rightParts[i];
}
System.out.println(ansi().bold().fg(Ansi.Color.GREEN) + left + ansi().boldOff().fg(Ansi.Color.WHITE) + " - " + ansi().bold() + StringUtils.join(rightParts, LINESEP));
}
System.out.println();
System.out.println(ansi().boldOff().fg(Ansi.Color.WHITE) + "See what options are available:");
System.out.println(" " + provideCommandName() + " help {command}");
System.out.println();
}
protected abstract String provideCommandName();
public List<BaseCommand> provideCommands() {
ArrayList<BaseCommand> commands = new ArrayList<>();
commands.add(new RunServerCommand());
commands.add(new ExampleDataUploader());
commands.add(new ValidateCommand());
commands.add(new ValidationDataUploader());
commands.add(new WebsocketSubscribeCommand());
commands.add(new UploadTerminologyCommand());
commands.add(new IgPackUploader());
return commands;
}
protected abstract String provideProductName();
protected abstract String provideProductVersion();
@SuppressWarnings("ResultOfMethodCallIgnored")
public void run(String[] theArgs) {
loggingConfigOff();
validateJavaVersion();
AnsiConsole.systemInstall();
// log version while the logging is off
VersionUtil.getVersion();
// Set up command list
ourCommands = new ArrayList<>();
ourCommands.addAll(provideCommands());
Collections.sort(ourCommands);
if (theArgs.length == 0) {
logUsage();
return;
}
if (theArgs[0].equals("help")) {
if (theArgs.length < 2) {
logUsage();
return;
}
BaseCommand command = null;
for (BaseCommand nextCommand : ourCommands) {
if (nextCommand.getCommandName().equals(theArgs[1])) {
command = nextCommand;
break;
}
}
if (command == null) {
System.err.println("Unknown command: " + theArgs[1]);
return;
}
logCommandUsage(command);
return;
}
BaseCommand command = null;
for (BaseCommand nextCommand : ourCommands) {
if (nextCommand.getCommandName().equals(theArgs[0])) {
command = nextCommand;
break;
}
}
if (command == null) {
System.out.println("Unrecognized command: " + ansi().bold().fg(Ansi.Color.RED) + theArgs[0] + ansi().boldOff().fg(Ansi.Color.WHITE));
System.out.println();
logUsage();
return;
}
Options options = command.getOptions();
DefaultParser parser = new DefaultParser();
CommandLine parsedOptions;
logAppHeader();
validateJavaVersion();
loggingConfigOn();
try {
String[] args = Arrays.copyOfRange(theArgs, 1, theArgs.length);
parsedOptions = parser.parse(options, args, true);
if (!parsedOptions.getArgList().isEmpty()) {
throw new ParseException("Unrecognized argument: " + parsedOptions.getArgList().get(0));
}
// Actually execute the command
command.run(parsedOptions);
if (!"true".equals(System.getProperty("test"))) {
System.exit(0);
}
} catch (ParseException e) {
loggingConfigOff();
System.err.println("Invalid command options for command: " + command.getCommandName());
System.err.println(" " + ansi().fg(Ansi.Color.RED).bold() + e.getMessage());
System.err.println("" + ansi().fg(Ansi.Color.WHITE).boldOff());
logCommandUsageNoHeader(command);
System.exit(1);
} catch (CommandFailureException e) {
ourLog.error(e.getMessage());
if ("true".equals(System.getProperty("test"))) {
throw e;
} else {
System.exit(1);
}
} catch (Exception e) {
ourLog.error("Error during execution: ", e);
if ("true".equals(System.getProperty("test"))) {
throw new CommandFailureException("Error: " + e.toString(), e);
} else {
System.exit(1);
}
}
}
private void validateJavaVersion() {
String specVersion = System.getProperty("java.specification.version");
double version = Double.parseDouble(specVersion);
if (version < 1.8) {
System.err.flush();
System.err.println(provideProductName() + " requires Java 1.8+ to run (detected " + specVersion + ")");
System.exit(1);
}
}
private static void loggingConfigOff() {
try {
JoranConfigurator configurator = new JoranConfigurator();
configurator.setContext((LoggerContext) LoggerFactory.getILoggerFactory());
configurator.doConfigure(App.class.getResourceAsStream("/logback-cli-off.xml"));
} catch (JoranException e) {
e.printStackTrace();
}
}
private static void loggingConfigOn() {
try {
JoranConfigurator configurator = new JoranConfigurator();
configurator.setContext((LoggerContext) LoggerFactory.getILoggerFactory());
((LoggerContext) LoggerFactory.getILoggerFactory()).reset();
configurator.doConfigure(App.class.getResourceAsStream("/logback-cli-on.xml"));
} catch (JoranException e) {
e.printStackTrace();
}
}
}

View File

@ -2,11 +2,15 @@ package ca.uhn.fhir.cli;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.client.interceptor.SimpleRequestHeaderInterceptor;
import com.google.common.base.Charsets;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
@ -16,21 +20,28 @@ import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.fusesource.jansi.Ansi;
import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Base64Utils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import java.util.zip.GZIPInputStream;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.*;
public abstract class BaseCommand implements Comparable<BaseCommand> {
private static final String SPEC_DEFAULT_VERSION = "dstu3";
public static final String BASE_URL_PARAM = "t";
public static final String BASIC_AUTH_OPTION = "b";
public static final String BASIC_AUTH_LONGOPT = "basic-auth";
public static final String BEARER_TOKEN_LONGOPT = "bearer-token";
public static final String FHIR_VERSION_OPTION = "v";
private static final Logger ourLog = LoggerFactory.getLogger(BaseCommand.class);
private FhirContext myFhirCtx;
@ -38,10 +49,57 @@ public abstract class BaseCommand implements Comparable<BaseCommand> {
super();
}
protected void addBasicAuthOption(Options theOptions) {
addOptionalOption(theOptions, BASIC_AUTH_OPTION, BASIC_AUTH_LONGOPT, true, "If specified, this parameter supplies a username and password (in the format \"username:password\") to include in an HTTP Basic Auth header");
addOptionalOption(theOptions, null, BEARER_TOKEN_LONGOPT, true, "If specified, this parameter supplies a Bearer Token to supply with the request");
}
protected void addFhirVersionOption(Options theOptions) {
Option opt = new Option("f", "fhirversion", true, "Spec version to upload (default is '" + SPEC_DEFAULT_VERSION + "')");
opt.setRequired(false);
theOptions.addOption(opt);
String versions = Arrays.stream(FhirVersionEnum.values())
.filter(t -> t != FhirVersionEnum.DSTU2_1 && t != FhirVersionEnum.DSTU2_HL7ORG)
.map(t -> t.name().toLowerCase())
.sorted()
.collect(Collectors.joining(", "));
addRequiredOption(theOptions, FHIR_VERSION_OPTION, "fhir-version", "version", "The FHIR version being used. Valid values: " + versions);
}
private void addOption(Options theOptions, boolean theRequired, String theOpt, String theLong, boolean theHasArgument, String theArgumentName, String theDescription) {
Option option = new Option(theOpt, theLong, theHasArgument, theDescription);
option.setRequired(theRequired);
if (theHasArgument && isNotBlank(theArgumentName)) {
option.setArgName(theArgumentName);
}
if (isNotBlank(theOpt)) {
if (theOptions.getOption(theOpt) != null) {
throw new IllegalStateException("Duplicate option: " + theOpt);
}
}
if (isNotBlank(theLong)) {
if (theOptions.getOption(theLong) != null) {
throw new IllegalStateException("Duplicate option: " + theLong);
}
}
theOptions.addOption(option);
}
protected void addOptionalOption(Options theOptions, String theOpt, String theLong, boolean theTakesArgument, String theDescription) {
addOption(theOptions, false, theOpt, theLong, theTakesArgument, null, theDescription);
}
protected void addOptionalOption(Options theOptions, String theOpt, String theLong, String theArgumentName, String theDescription) {
addOption(theOptions, false, theOpt, theLong, isNotBlank(theArgumentName), theArgumentName, theDescription);
}
protected void addRequiredOption(Options theOptions, String theOpt, String theLong, boolean theTakesArgument, String theDescription) {
addOption(theOptions, true, theOpt, theLong, theTakesArgument, null, theDescription);
}
protected void addRequiredOption(Options theOptions, String theOpt, String theLong, String theArgumentName, String theDescription) {
boolean hasArgument = isNotBlank(theArgumentName);
boolean required = true;
addOption(theOptions, required, theOpt, theLong, hasArgument, theArgumentName, theDescription);
}
@Override
@ -49,6 +107,18 @@ public abstract class BaseCommand implements Comparable<BaseCommand> {
return getCommandName().compareTo(theO.getCommandName());
}
protected Reader createReader(File theInputFile) throws IOException {
InputStream inputStream = new FileInputStream(theInputFile);
if (theInputFile.getName().toLowerCase().endsWith(".gz")) {
inputStream = new GZIPInputStream(inputStream);
}
if (theInputFile.getName().toLowerCase().endsWith(".bz2")) {
inputStream = new BZip2CompressorInputStream(inputStream);
}
return new InputStreamReader(inputStream, Charsets.UTF_8);
}
private void downloadFileFromInternet(CloseableHttpResponse result, File localFile) throws IOException {
FileOutputStream buffer = FileUtils.openOutputStream(localFile);
try {
@ -88,40 +158,73 @@ public abstract class BaseCommand implements Comparable<BaseCommand> {
}
}
/**
* @return Returns the complete authorization header value using the "-b" option
*/
protected String getAndParseOptionBasicAuthHeader(CommandLine theCommandLine) {
return getAndParseOptionBasicAuthHeader(theCommandLine, BASIC_AUTH_OPTION);
}
/**
* @return Returns the complete authorization header value using an arbitrary option
*/
protected String getAndParseOptionBasicAuthHeader(CommandLine theCommandLine, String theOptionName) {
String basicAuthHeaderValue = null;
if (theCommandLine.hasOption(theOptionName)) {
byte[] basicAuth = theCommandLine.getOptionValue(theOptionName).getBytes();
String base64EncodedBasicAuth = Base64Utils.encodeToString(basicAuth);
basicAuthHeaderValue = Constants.HEADER_AUTHORIZATION_VALPREFIX_BASIC + base64EncodedBasicAuth;
} else {
basicAuthHeaderValue = null;
}
return basicAuthHeaderValue;
}
public <T extends Enum> T getAndParseOptionEnum(CommandLine theCommandLine, String theOption, Class<T> theEnumClass, T theDefault) throws ParseException {
String val = theCommandLine.getOptionValue(theOption);
if (isBlank(val)) {
return theDefault;
}
try {
return (T) Enum.valueOf(theEnumClass, val);
} catch (Exception e) {
throw new ParseException("Invalid option \"" + val + "\" for option -" + theOption);
}
}
public Integer getAndParsePositiveIntegerParam(CommandLine theCommandLine, String theName) throws ParseException {
String value = theCommandLine.getOptionValue(theName);
value = trim(value);
if (isBlank(value)) {
return null;
}
try {
int valueInt = Integer.parseInt(value);
if (valueInt < 1) {
throw new ParseException("Value for argument " + theName + " must be a positive integer, got: " + value);
}
return valueInt;
} catch (NumberFormatException e) {
throw new ParseException("Value for argument " + theName + " must be a positive integer, got: " + value);
}
}
public Class<? extends IBaseBundle> getBundleTypeForFhirVersion() {
return getFhirContext().getResourceDefinition("Bundle").getImplementingClass(IBaseBundle.class);
}
public abstract String getCommandDescription();
public abstract String getCommandName();
public abstract Options getOptions();
protected FhirContext getSpecVersionContext(CommandLine theCommandLine) throws ParseException {
if (myFhirCtx == null) {
String specVersion = theCommandLine.getOptionValue("f", SPEC_DEFAULT_VERSION);
specVersion = specVersion.toLowerCase();
FhirVersionEnum version;
if ("dstu2".equals(specVersion)) {
version = FhirVersionEnum.DSTU2;
} else if ("dstu3".equals(specVersion)) {
version = FhirVersionEnum.DSTU3;
} else if ("r4".equals(specVersion)) {
version = FhirVersionEnum.R4;
} else {
throw new ParseException("Unknown spec version: " + specVersion);
}
myFhirCtx = new FhirContext(version);
}
protected FhirContext getFhirContext() {
return myFhirCtx;
}
// public FhirContext getFhirCtx() {
// if (myFhirCtx == null) {
// myFhirCtx = FhirContext.forDstu2();
// }
// return myFhirCtx;
// }
public abstract Options getOptions();
protected Collection<File> loadFile(FhirContext theCtx, String theSpecUrl, String theFilepath, boolean theCacheFile) throws IOException {
protected Collection<File> loadFile(String theSpecUrl, String theFilepath, boolean theCacheFile) throws IOException {
String userHomeDir = System.getProperty("user.home");
File applicationDir = new File(userHomeDir + File.separator + "." + "hapi-fhir-cli");
@ -138,7 +241,7 @@ public abstract class BaseCommand implements Comparable<BaseCommand> {
File suppliedFile = new File(FilenameUtils.normalize(theFilepath));
if (suppliedFile.isDirectory()) {
inputFiles = FileUtils.listFiles(suppliedFile, new String[]{"zip"}, false);
inputFiles = FileUtils.listFiles(suppliedFile, new String[] {"zip"}, false);
} else {
inputFiles = Collections.singletonList(suppliedFile);
}
@ -148,13 +251,13 @@ public abstract class BaseCommand implements Comparable<BaseCommand> {
File cacheDir = new File(applicationDir, "cache");
FileUtils.forceMkdir(cacheDir);
File inputFile = new File(cacheDir, "examples-json-" + theCtx.getVersion().getVersion() + ".zip");
File inputFile = new File(cacheDir, "examples-json-" + getFhirContext().getVersion().getVersion() + ".zip");
Date cacheExpiryDate = DateUtils.addHours(new Date(), -12);
if (!inputFile.exists() | (theCacheFile && FileUtils.isFileOlder(inputFile, cacheExpiryDate))) {
File exampleFileDownloading = new File(cacheDir, "examples-json-" + theCtx.getVersion().getVersion() + ".zip.partial");
File exampleFileDownloading = new File(cacheDir, "examples-json-" + getFhirContext().getVersion().getVersion() + ".zip.partial");
HttpGet get = new HttpGet(theSpecUrl);
CloseableHttpClient client = HttpClientBuilder.create().build();
@ -184,12 +287,46 @@ public abstract class BaseCommand implements Comparable<BaseCommand> {
return inputFiles;
}
protected IGenericClient newClient(FhirContext ctx, String theBaseUrl) {
ctx.getRestfulClientFactory().setSocketTimeout(10 * 60 * 1000);
IGenericClient fhirClient = ctx.newRestfulGenericClient(theBaseUrl);
return fhirClient;
protected IGenericClient newClient(CommandLine theCommandLine) {
return newClient(theCommandLine, BASE_URL_PARAM, BASIC_AUTH_OPTION, BEARER_TOKEN_LONGOPT);
}
public abstract void run(CommandLine theCommandLine) throws ParseException, Exception;
protected IGenericClient newClient(CommandLine theCommandLine, String theBaseUrlParamName, String theBasicAuthOptionName, String theBearerTokenOptionName) {
String baseUrl = theCommandLine.getOptionValue(theBaseUrlParamName);
myFhirCtx.getRestfulClientFactory().setSocketTimeout(10 * 60 * 1000);
IGenericClient retVal = myFhirCtx.newRestfulGenericClient(baseUrl);
String basicAuthHeaderValue = getAndParseOptionBasicAuthHeader(theCommandLine, theBasicAuthOptionName);
if (isNotBlank(basicAuthHeaderValue)) {
retVal.registerInterceptor(new SimpleRequestHeaderInterceptor(Constants.HEADER_AUTHORIZATION, basicAuthHeaderValue));
}
if (isNotBlank(theBearerTokenOptionName)) {
String bearerToken = theCommandLine.getOptionValue(theBearerTokenOptionName);
if (isNotBlank(bearerToken)) {
retVal.registerInterceptor(new SimpleRequestHeaderInterceptor(Constants.HEADER_AUTHORIZATION, Constants.HEADER_AUTHORIZATION_VALPREFIX_BEARER + bearerToken));
}
}
return retVal;
}
protected void parseFhirContext(CommandLine theCommandLine) throws ParseException {
String version = theCommandLine.getOptionValue(FHIR_VERSION_OPTION);
if (isBlank(version)) {
throw new ParseException("Missing required option: -" + FHIR_VERSION_OPTION);
}
try {
FhirVersionEnum versionEnum = FhirVersionEnum.valueOf(version.toUpperCase());
myFhirCtx = versionEnum.newContext();
} catch (Exception e) {
throw new ParseException("Invalid FHIR version string: " + version);
}
}
public abstract void run(CommandLine theCommandLine) throws ParseException, ExecutionException;
}

View File

@ -2,6 +2,10 @@ package ca.uhn.fhir.cli;
public class CommandFailureException extends Error {
public CommandFailureException(Throwable theCause) {
super(theCause.getMessage(), theCause);
}
public CommandFailureException(String theMessage) {
super(theMessage);
}

View File

@ -33,7 +33,6 @@ import org.hl7.fhir.dstu3.model.Resource;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import java.io.*;
import java.util.*;
@ -327,6 +326,8 @@ public class ExampleDataUploader extends BaseCommand {
opt.setRequired(false);
options.addOption(opt);
addBasicAuthOption(options);
return options;
}
@ -573,8 +574,9 @@ public class ExampleDataUploader extends BaseCommand {
}
@Override
public void run(CommandLine theCommandLine) throws Exception {
FhirContext ctx = getSpecVersionContext(theCommandLine);
public void run(CommandLine theCommandLine) throws ParseException {
parseFhirContext(theCommandLine);
FhirContext ctx = getFhirContext();
String targetServer = theCommandLine.getOptionValue("t");
if (isBlank(targetServer)) {
@ -613,17 +615,22 @@ public class ExampleDataUploader extends BaseCommand {
boolean cacheFile = theCommandLine.hasOption('c');
Collection<File> inputFiles = loadFile(ctx, specUrl, filepath, cacheFile);
for (File inputFile : inputFiles) {
IBaseBundle bundle = getBundleFromFile(limit, inputFile, ctx);
processBundle(ctx, bundle);
sendBundleToTarget(targetServer, ctx, bundle);
Collection<File> inputFiles = null;
try {
inputFiles = loadFile(specUrl, filepath, cacheFile);
for (File inputFile : inputFiles) {
IBaseBundle bundle = getBundleFromFile(limit, inputFile, ctx);
processBundle(ctx, bundle);
sendBundleToTarget(targetServer, ctx, bundle, theCommandLine);
}
} catch (Exception e) {
throw new CommandFailureException(e);
}
}
private void sendBundleToTarget(String targetServer, FhirContext ctx, IBaseBundle bundle) throws Exception {
private void sendBundleToTarget(String targetServer, FhirContext ctx, IBaseBundle bundle, CommandLine theCommandLine) throws Exception {
List<IBaseResource> resources = BundleUtil.toListOfResources(ctx, bundle);
for (Iterator<IBaseResource> iter = resources.iterator(); iter.hasNext(); ) {
@ -707,7 +714,7 @@ public class ExampleDataUploader extends BaseCommand {
} else {
ourLog.info("Uploading bundle to server: " + targetServer);
IGenericClient fhirClient = newClient(ctx, targetServer);
IGenericClient fhirClient = newClient(theCommandLine);
fhirClient.registerInterceptor(new GZipContentInterceptor());
long start = System.currentTimeMillis();

View File

@ -3,6 +3,7 @@ package ca.uhn.fhir.cli;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.igpacks.parser.IgPackParserDstu3;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import net.sf.ehcache.transaction.xa.commands.Command;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
@ -16,6 +17,8 @@ import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Collection;
public class IgPackUploader extends BaseCommand {
@ -48,20 +51,31 @@ public class IgPackUploader extends BaseCommand {
}
@Override
public void run(CommandLine theCommandLine) throws ParseException, Exception {
FhirContext ctx = getSpecVersionContext(theCommandLine);
public void run(CommandLine theCommandLine) throws ParseException{
parseFhirContext(theCommandLine);
String targetServer = theCommandLine.getOptionValue("t");
IGenericClient client = ctx.newRestfulGenericClient(targetServer);
IGenericClient client = newClient(theCommandLine);
String url = theCommandLine.getOptionValue("u");
Collection<File> files = loadFile(ctx, url, null, false);
Collection<File> files = null;
try {
files = loadFile(url, null, false);
} catch (IOException e) {
throw new CommandFailureException(e);
}
for (File nextFile : files) {
FhirContext ctx = getFhirContext();
switch (ctx.getVersion().getVersion()) {
case DSTU3:
IgPackParserDstu3 packParser = new IgPackParserDstu3(ctx);
IValidationSupport ig = packParser.parseIg(new FileInputStream(nextFile), nextFile.getName());
IValidationSupport ig = null;
try {
ig = packParser.parseIg(new FileInputStream(nextFile), nextFile.getName());
} catch (FileNotFoundException e) {
throw new CommandFailureException(e);
}
Iterable<IBaseResource> conformanceResources = ig.fetchAllConformanceResources(ctx);
for (IBaseResource nextResource : conformanceResources) {
String nextResourceUrl = ((IPrimitiveType<?>)ctx.newTerser().getSingleValueOrNull(nextResource, "url")).getValueAsString();

View File

@ -34,13 +34,14 @@ public class RunServerCommand extends BaseCommand {
private static final String OPTION_P = "p";
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RunServerCommand.class);
public static final String RUN_SERVER_COMMAND = "run-server";
private int myPort;
private Server myServer;
@Override
public String getCommandName() {
return "run-server";
return RUN_SERVER_COMMAND;
}
@Override
@ -68,6 +69,8 @@ public class RunServerCommand extends BaseCommand {
@Override
public void run(CommandLine theCommandLine) throws ParseException {
parseFhirContext(theCommandLine);
myPort = parseOptionInteger(theCommandLine, OPTION_P, DEFAULT_PORT);
if (theCommandLine.hasOption(OPTION_LOWMEM)) {
@ -104,7 +107,7 @@ public class RunServerCommand extends BaseCommand {
}
}
ContextHolder.setCtx(getSpecVersionContext(theCommandLine));
ContextHolder.setCtx(getFhirContext());
ourLog.info("Preparing HAPI FHIR JPA server on port {}", myPort);
File tempWarFile;

View File

@ -1,28 +1,32 @@
package ca.uhn.fhir.cli;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import org.apache.commons.cli.*;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.instance.model.api.IBaseParameters;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.client.interceptor.BearerTokenAuthInterceptor;
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.hl7.fhir.dstu3.model.Parameters;
import org.hl7.fhir.dstu3.model.StringType;
import org.hl7.fhir.dstu3.model.UriType;
import org.hl7.fhir.instance.model.api.IBaseParameters;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class UploadTerminologyCommand extends BaseCommand {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(UploadTerminologyCommand.class);
private static final String BASE_URL_PARAM = "t";
private static final String UPLOAD_EXTERNAL_CODE_SYSTEM = "upload-external-code-system";
@Override
public String getCommandDescription() {
return "Uploads a terminology package (e.g. a SNOMED CT ZIP file) to a HAPI JPA server. "
+ "Note that this command uses a custom operation that is only implemented on HAPI "
+ "JPA servers that have been configured to accept it.";
return "Uploads a terminology package (e.g. a SNOMED CT ZIP file) to a server, using the $" + UPLOAD_EXTERNAL_CODE_SYSTEM + " operation.";
}
@Override
@ -45,28 +49,27 @@ public class UploadTerminologyCommand extends BaseCommand {
opt.setRequired(false);
options.addOption(opt);
opt = new Option("d", "data", true, "Local *.zip containing file to use to upload");
opt = new Option("d", "data", true, "Local file to use to upload (can be a raw file or a ZIP containing the raw file)");
opt.setRequired(false);
options.addOption(opt);
opt = new Option("b", "bearer-token", true, "Bearer token to add to the request");
opt.setRequired(false);
options.addOption(opt);
addBasicAuthOption(options);
opt = new Option("v", "verbose", false, "Verbose output");
opt.setRequired(false);
options.addOption(opt);
return options;
}
@Override
public void run(CommandLine theCommandLine) throws Exception {
FhirContext ctx = getSpecVersionContext(theCommandLine);
public void run(CommandLine theCommandLine) throws ParseException {
parseFhirContext(theCommandLine);
FhirContext ctx = getFhirContext();
String targetServer = theCommandLine.getOptionValue("t");
String targetServer = theCommandLine.getOptionValue(BASE_URL_PARAM);
if (isBlank(targetServer)) {
throw new ParseException("No target server (-t) specified");
throw new ParseException("No target server (-" + BASE_URL_PARAM + ") specified");
} else if (targetServer.startsWith("http") == false && targetServer.startsWith("file") == false) {
throw new ParseException("Invalid target server specified, must begin with 'http' or 'file'");
}
@ -75,15 +78,15 @@ public class UploadTerminologyCommand extends BaseCommand {
if (isBlank(termUrl)) {
throw new ParseException("No URL provided");
}
String[] datafile = theCommandLine.getOptionValues("d");
if (datafile == null || datafile.length == 0) {
throw new ParseException("No data file provided");
}
String bearerToken = theCommandLine.getOptionValue("b");
IGenericClient client = super.newClient(ctx, targetServer);
IGenericClient client = super.newClient(theCommandLine);
IBaseParameters inputParameters;
if (ctx.getVersion().getVersion() == FhirVersionEnum.DSTU3) {
Parameters p = new Parameters();
@ -103,12 +106,12 @@ public class UploadTerminologyCommand extends BaseCommand {
if (theCommandLine.hasOption('v')) {
client.registerInterceptor(new LoggingInterceptor(true));
}
ourLog.info("Beginning upload - This may take a while...");
IBaseParameters response = client
.operation()
.onServer()
.named("upload-external-code-system")
.named(UPLOAD_EXTERNAL_CODE_SYSTEM)
.withParameters(inputParameters)
.execute();

View File

@ -1,22 +1,24 @@
package ca.uhn.fhir.cli;
import static org.apache.commons.lang3.StringUtils.*;
import static org.fusesource.jansi.Ansi.ansi;
import java.io.*;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.SingleValidationMessage;
import ca.uhn.fhir.validation.ValidationResult;
import com.phloc.commons.io.file.FileUtils;
import org.apache.commons.cli.*;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.text.WordUtils;
import org.fusesource.jansi.Ansi.Color;
import org.hl7.fhir.dstu3.hapi.validation.*;
import org.hl7.fhir.dstu3.hapi.validation.DefaultProfileValidationSupport;
import org.hl7.fhir.dstu3.hapi.validation.FhirInstanceValidator;
import org.hl7.fhir.dstu3.hapi.validation.ValidationSupportChain;
import org.hl7.fhir.dstu3.model.StructureDefinition;
import org.hl7.fhir.instance.model.api.IBaseResource;
import com.phloc.commons.io.file.FileUtils;
import java.io.*;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.validation.*;
import static org.apache.commons.lang3.StringUtils.*;
import static org.fusesource.jansi.Ansi.ansi;
public class ValidateCommand extends BaseCommand {
@ -54,7 +56,9 @@ public class ValidateCommand extends BaseCommand {
}
@Override
public void run(CommandLine theCommandLine) throws ParseException, Exception {
public void run(CommandLine theCommandLine) throws ParseException {
parseFhirContext(theCommandLine);
String fileName = theCommandLine.getOptionValue("n");
String contents = theCommandLine.getOptionValue("c");
if (isNotBlank(fileName) && isNotBlank(contents)) {
@ -68,7 +72,11 @@ public class ValidateCommand extends BaseCommand {
String encoding = theCommandLine.getOptionValue("e", "UTF-8");
ourLog.info("Reading file '{}' using encoding {}", fileName, encoding);
contents = IOUtils.toString(new InputStreamReader(new FileInputStream(fileName), encoding));
try {
contents = IOUtils.toString(new InputStreamReader(new FileInputStream(fileName), encoding));
} catch (IOException e) {
throw new CommandFailureException(e);
}
ourLog.info("Fully read - Size is {}", FileUtils.getFileSizeDisplay(contents.length()));
}
@ -77,7 +85,7 @@ public class ValidateCommand extends BaseCommand {
throw new ParseException("Could not detect encoding (json/xml) of contents");
}
FhirContext ctx = getSpecVersionContext(theCommandLine);
FhirContext ctx = getFhirContext();
FhirValidator val = ctx.newValidator();
IBaseResource localProfileResource = null;

View File

@ -100,10 +100,12 @@ public class ValidationDataUploader extends BaseCommand {
addFhirVersionOption(options);
opt = new Option("t", "target", true, "Base URL for the target server (e.g. \"http://example.com/fhir\")");
opt = new Option(BASE_URL_PARAM, "target", true, "Base URL for the target server (e.g. \"http://example.com/fhir\")");
opt.setRequired(true);
options.addOption(opt);
addBasicAuthOption(options);
opt = new Option("e", "exclude", true, "Exclude uploading the given resources, e.g. \"-e dicom-dcim,foo\"");
opt.setRequired(false);
options.addOption(opt);
@ -113,6 +115,8 @@ public class ValidationDataUploader extends BaseCommand {
@Override
public void run(CommandLine theCommandLine) throws ParseException {
parseFhirContext(theCommandLine);
String targetServer = theCommandLine.getOptionValue("t");
if (isBlank(targetServer)) {
throw new ParseException("No target server (-t) specified");
@ -120,7 +124,7 @@ public class ValidationDataUploader extends BaseCommand {
throw new ParseException("Invalid target server specified, must begin with 'http'");
}
FhirContext ctx = getSpecVersionContext(theCommandLine);
FhirContext ctx = getFhirContext();
String exclude = theCommandLine.getOptionValue("e");
if (isNotBlank(exclude)) {
@ -134,18 +138,19 @@ public class ValidationDataUploader extends BaseCommand {
}
if (ctx.getVersion().getVersion() == FhirVersionEnum.DSTU2) {
uploadDefinitionsDstu2(targetServer, ctx);
uploadDefinitionsDstu2(theCommandLine, ctx);
} else if (ctx.getVersion().getVersion() == FhirVersionEnum.DSTU3) {
uploadDefinitionsDstu3(targetServer, ctx);
uploadDefinitionsDstu3(theCommandLine, ctx);
} else if (ctx.getVersion().getVersion() == FhirVersionEnum.R4) {
uploadDefinitionsR4(targetServer, ctx);
uploadDefinitionsR4(theCommandLine, ctx);
}
}
private void uploadDefinitionsDstu2(String targetServer, FhirContext ctx) throws CommandFailureException {
IGenericClient client = newClient(ctx, targetServer);
ourLog.info("Uploading definitions to server: " + targetServer);
private void uploadDefinitionsDstu2(CommandLine theCommandLine, FhirContext ctx) throws CommandFailureException {
IGenericClient client = newClient(theCommandLine);
ourLog.info("Uploading definitions to server");
long start = System.currentTimeMillis();
@ -242,9 +247,9 @@ public class ValidationDataUploader extends BaseCommand {
ourLog.info("Finished uploading definitions to server (took {} ms)", delay);
}
private void uploadDefinitionsDstu3(String targetServer, FhirContext ctx) throws CommandFailureException {
IGenericClient client = newClient(ctx, targetServer);
ourLog.info("Uploading definitions to server: " + targetServer);
private void uploadDefinitionsDstu3(CommandLine theCommandLine, FhirContext theCtx) throws CommandFailureException {
IGenericClient client = newClient(theCommandLine);
ourLog.info("Uploading definitions to server");
long start = System.currentTimeMillis();
int total = 0;
@ -253,12 +258,12 @@ public class ValidationDataUploader extends BaseCommand {
String vsContents;
try {
ctx.getVersion().getPathToSchemaDefinitions();
theCtx.getVersion().getPathToSchemaDefinitions();
vsContents = IOUtils.toString(ValidationDataUploader.class.getResourceAsStream("/org/hl7/fhir/dstu3/model/valueset/" + "valuesets.xml"), "UTF-8");
} catch (IOException e) {
throw new CommandFailureException(e.toString());
}
bundle = ctx.newXmlParser().parseResource(org.hl7.fhir.dstu3.model.Bundle.class, vsContents);
bundle = theCtx.newXmlParser().parseResource(org.hl7.fhir.dstu3.model.Bundle.class, vsContents);
filterBundle(bundle);
total = bundle.getEntry().size();
@ -267,7 +272,7 @@ public class ValidationDataUploader extends BaseCommand {
org.hl7.fhir.dstu3.model.Resource next = i.getResource();
next.setId(next.getIdElement().toUnqualifiedVersionless());
int bytes = ctx.newXmlParser().encodeResourceToString(next).length();
int bytes = theCtx.newXmlParser().encodeResourceToString(next).length();
ourLog.info("Uploading ValueSet {}/{} : {} ({} bytes}", new Object[] {count, total, next.getIdElement().getValue(), bytes});
try {
@ -287,7 +292,7 @@ public class ValidationDataUploader extends BaseCommand {
throw new CommandFailureException(e.toString());
}
bundle = ctx.newXmlParser().parseResource(org.hl7.fhir.dstu3.model.Bundle.class, vsContents);
bundle = theCtx.newXmlParser().parseResource(org.hl7.fhir.dstu3.model.Bundle.class, vsContents);
filterBundle(bundle);
total = bundle.getEntry().size();
@ -310,7 +315,7 @@ public class ValidationDataUploader extends BaseCommand {
} catch (IOException e) {
throw new CommandFailureException(e.toString());
}
bundle = ctx.newXmlParser().parseResource(org.hl7.fhir.dstu3.model.Bundle.class, vsContents);
bundle = theCtx.newXmlParser().parseResource(org.hl7.fhir.dstu3.model.Bundle.class, vsContents);
filterBundle(bundle);
total = bundle.getEntry().size();
count = 1;
@ -329,9 +334,9 @@ public class ValidationDataUploader extends BaseCommand {
ourLog.info("Finished uploading ValueSets");
uploadDstu3Profiles(ctx, client, "profiles-resources");
uploadDstu3Profiles(ctx, client, "profiles-types");
uploadDstu3Profiles(ctx, client, "profiles-others");
uploadDstu3Profiles(theCtx, client, "profiles-resources");
uploadDstu3Profiles(theCtx, client, "profiles-types");
uploadDstu3Profiles(theCtx, client, "profiles-others");
ourLog.info("Finished uploading ValueSets");
@ -340,9 +345,9 @@ public class ValidationDataUploader extends BaseCommand {
ourLog.info("Finished uploading definitions to server (took {} ms)", delay);
}
private void uploadDefinitionsR4(String theTargetServer, FhirContext theCtx) throws CommandFailureException {
IGenericClient client = newClient(theCtx, theTargetServer);
ourLog.info("Uploading definitions to server: " + theTargetServer);
private void uploadDefinitionsR4(CommandLine theCommandLine, FhirContext theCtx) throws CommandFailureException {
IGenericClient client = newClient(theCommandLine);
ourLog.info("Uploading definitions to server");
long start = System.currentTimeMillis();
int total = 0;

View File

@ -1,30 +1,22 @@
package ca.uhn.fhir.cli;
import static org.apache.commons.lang3.StringUtils.isBlank;
import java.net.URI;
import ca.uhn.fhir.model.primitive.IdDt;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketFrame;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.api.annotations.*;
import org.eclipse.jetty.websocket.api.extensions.Frame;
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import ca.uhn.fhir.model.primitive.IdDt;
import java.net.URI;
import static org.apache.commons.lang3.StringUtils.isBlank;
public class WebsocketSubscribeCommand extends BaseCommand {
private static final org.slf4j.Logger LOG_RECV = org.slf4j.LoggerFactory.getLogger("websocket.RECV");
private static final org.slf4j.Logger LOG_SEND = org.slf4j.LoggerFactory.getLogger("websocket.SEND");
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(WebsocketSubscribeCommand.class);
private boolean myQuit;
@ -38,6 +30,7 @@ public class WebsocketSubscribeCommand extends BaseCommand {
public String getCommandName() {
return "subscription-client";
}
@Override
public Options getOptions() {
Options options = new Options();
@ -45,15 +38,16 @@ public class WebsocketSubscribeCommand extends BaseCommand {
options.addOption("i", "subscriptionid", true, "Subscription ID, e.g. \"5235\"");
return options;
}
@Override
public void run(CommandLine theCommandLine) throws ParseException, Exception {
public void run(CommandLine theCommandLine) throws ParseException {
String target = theCommandLine.getOptionValue("t");
if (isBlank(target) || (!target.startsWith("ws://") && !target.startsWith("wss://"))) {
throw new ParseException("Target (-t) needs to be in the form \"ws://foo\" or \"wss://foo\"");
}
IdDt subsId = new IdDt(theCommandLine.getOptionValue("i"));
WebSocketClient client = new WebSocketClient();
SimpleEchoSocket socket = new SimpleEchoSocket(subsId.getIdPart());
try {
@ -68,6 +62,8 @@ public class WebsocketSubscribeCommand extends BaseCommand {
}
ourLog.info("Shutting down websocket client");
} catch (Exception e) {
throw new CommandFailureException(e);
} finally {
try {
client.stop();
@ -76,7 +72,7 @@ public class WebsocketSubscribeCommand extends BaseCommand {
}
}
}
/**
* Basic Echo Client Socket
*/
@ -84,7 +80,7 @@ public class WebsocketSubscribeCommand extends BaseCommand {
public class SimpleEchoSocket {
private String mySubsId;
@SuppressWarnings("unused")
private Session session;
@ -93,17 +89,6 @@ public class WebsocketSubscribeCommand extends BaseCommand {
mySubsId = theSubsId;
}
@OnWebSocketError
public void onError(Throwable theError) {
ourLog.error("Websocket error: ", theError);
myQuit = true;
}
@OnWebSocketFrame
public void onFrame(Frame theFrame) {
ourLog.debug("Websocket frame: {}", theFrame);
}
@OnWebSocketClose
public void onClose(int statusCode, String reason) {
ourLog.info("Received CLOSE status={} reason={}", statusCode, reason);
@ -123,10 +108,21 @@ public class WebsocketSubscribeCommand extends BaseCommand {
}
}
@OnWebSocketError
public void onError(Throwable theError) {
ourLog.error("Websocket error: ", theError);
myQuit = true;
}
@OnWebSocketFrame
public void onFrame(Frame theFrame) {
ourLog.debug("Websocket frame: {}", theFrame);
}
@OnWebSocketMessage
public void onMessage(String theMsg) {
LOG_RECV.info("{}", theMsg);
}
}
}

View File

@ -3,12 +3,15 @@
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<useJansi>true</useJansi>
<encoder>
<pattern>%boldGreen(%d{HH:mm:ss}) %white(%-5level) %logger{36} - %boldWhite(%msg%n)
<pattern>%green(%d{yyyy-MM-dd}) %boldGreen(%d{HH:mm:ss}) %white([%thread]) %white(%-5level) %boldBlue(%logger{20}) %boldWhite(%msg%n)
</pattern>
</encoder>
</appender>
<logger name="ca.uhn.fhir" additivity="false" level="info">
<logger name="ca.uhn.fhir.cli" additivity="false" level="info">
<appender-ref ref="STDOUT" />
</logger>
<logger name="ca.cdr.cli" additivity="false" level="info">
<appender-ref ref="STDOUT" />
</logger>
@ -20,6 +23,15 @@
<appender-ref ref="STDOUT" />
</logger>
<!-- These two are used by SynchronizeFhirServersCommand -->
<logger name="sync.SOURCE" additivity="false" level="info">
<appender-ref ref="STDOUT" />
</logger>
<logger name="sync.TARGET" additivity="false" level="info">
<appender-ref ref="STDOUT" />
</logger>
<root level="warn">
<appender-ref ref="STDOUT" />
</root>

View File

@ -127,6 +127,9 @@ fi
SCRIPTDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
COLUMNS=$(tput cols)
exec "$JAVACMD" \
-Dcolumns=$COLUMNS \
$CLI_OPTS \
-jar $SCRIPTDIR/hapi-fhir-cli.jar "$@"

View File

@ -1,3 +1,5 @@
package ca.uhn.fhir.cli;
import org.junit.Test;
public class InstallIgPackTest {

View File

@ -0,0 +1,15 @@
package ca.uhn.fhir.cli;
import org.junit.Test;
public class OptionsTest {
@Test
public void testOptions() {
App app = new App();
for (BaseCommand next : app.provideCommands()) {
next.getOptions();
}
}
}

View File

@ -1,8 +1,8 @@
package ca.uhn.fhir.cli;
import org.junit.Before;
import org.junit.Test;
import ca.uhn.fhir.cli.App;
public class ValidateTest {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ValidateTest.class);
@ -16,7 +16,7 @@ public class ValidateTest {
String resourcePath = ValidateTest.class.getResource("/patient-uslab-example1.xml").getFile();
ourLog.info(resourcePath);
App.main(new String[] {"validate", "-p", "-n", resourcePath});
App.main(new String[] {"validate", "-v", "dstu3", "-p", "-n", resourcePath});
}

View File

@ -593,6 +593,11 @@
<artifactId>commons-codec</artifactId>
<version>${commons_codec_version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.14</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>