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 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()); Collections.sort(ourCommands); } private static void logCommandUsage(BaseCommand theCommand) { logAppHeader(); logCommandUsageNoHeader(theCommand); } 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("------------------------------------------------------------"); } 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); } } 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); } } }