-
- com.google.auto.service
- auto-service-annotations
-
-
com.github.spotbugsspotbugs-annotations
diff --git a/databind-metaschema/src/main/java/gov/nist/secauto/metaschema/modules/sarif/SarifValidationHandler.java b/databind-metaschema/src/main/java/gov/nist/secauto/metaschema/modules/sarif/SarifValidationHandler.java
index 3211cf8e7..31b4e779b 100644
--- a/databind-metaschema/src/main/java/gov/nist/secauto/metaschema/modules/sarif/SarifValidationHandler.java
+++ b/databind-metaschema/src/main/java/gov/nist/secauto/metaschema/modules/sarif/SarifValidationHandler.java
@@ -45,6 +45,7 @@
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
+import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
@@ -56,6 +57,10 @@
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
+/**
+ * Supports building a Static Analysis Results Interchange Format (SARIF)
+ * document based on a set of validation findings.
+ */
@SuppressWarnings("PMD.CouplingBetweenObjects")
public final class SarifValidationHandler {
private enum Kind {
@@ -99,15 +104,15 @@ public String getLabel() {
}
@NonNull
- public static final String SARIF_NS = "https://docs.oasis-open.org/sarif/sarif/v2.1.0";
+ static final String SARIF_NS = "https://docs.oasis-open.org/sarif/sarif/v2.1.0";
@NonNull
- public static final IAttributable.Key SARIF_HELP_URL_KEY
+ static final IAttributable.Key SARIF_HELP_URL_KEY
= IAttributable.key("help-url", SARIF_NS);
@NonNull
- public static final IAttributable.Key SARIF_HELP_TEXT_KEY
+ static final IAttributable.Key SARIF_HELP_TEXT_KEY
= IAttributable.key("help-text", SARIF_NS);
@NonNull
- public static final IAttributable.Key SARIF_HELP_MARKDOWN_KEY
+ static final IAttributable.Key SARIF_HELP_MARKDOWN_KEY
= IAttributable.key("help-markdown", SARIF_NS);
@NonNull
@@ -131,6 +136,15 @@ public String getLabel() {
private final SchemaRuleRecord schemaRule = new SchemaRuleRecord();
private boolean schemaValid = true;
+ /**
+ * Construct a new validation handler.
+ *
+ * @param source
+ * the URI of the content that was validated
+ * @param toolVersion
+ * the version information for the tool producing the validation
+ * results
+ */
public SarifValidationHandler(
@NonNull URI source,
@Nullable IVersionInfo toolVersion) {
@@ -147,17 +161,29 @@ private URI getSource() {
return source;
}
- public IVersionInfo getToolVersion() {
+ private IVersionInfo getToolVersion() {
return toolVersion;
}
- public void addFindings(@NonNull List extends IValidationFinding> findings) {
+ /**
+ * Register a collection of validation finding.
+ *
+ * @param findings
+ * the findings to register
+ */
+ public void addFindings(@NonNull Collection extends IValidationFinding> findings) {
for (IValidationFinding finding : findings) {
assert finding != null;
addFinding(finding);
}
}
+ /**
+ * Register a validation finding.
+ *
+ * @param finding
+ * the finding to register
+ */
public void addFinding(@NonNull IValidationFinding finding) {
if (finding instanceof JsonValidationFinding) {
addJsonValidationFinding((JsonValidationFinding) finding);
@@ -207,7 +233,20 @@ private void addConstraintValidationFinding(@NonNull ConstraintValidationFinding
results.add(new ConstraintResult(finding));
}
- public void write(@NonNull Path outputFile) throws IOException {
+ /**
+ * Write the collection of findings to the provided output file.
+ *
+ * @param outputFile
+ * the path to the output file to write to
+ * @param bindingContext
+ * the context used to access Metaschema module information based on
+ * Java class bindings
+ * @throws IOException
+ * if an error occurred while writing the SARIF file
+ */
+ public void write(
+ @NonNull Path outputFile,
+ @NonNull IBindingContext bindingContext) throws IOException {
URI output = ObjectUtils.notNull(outputFile.toUri());
@@ -246,7 +285,6 @@ public void write(@NonNull Path outputFile) throws IOException {
run.setTool(tool);
}
- IBindingContext bindingContext = IBindingContext.newInstance();
bindingContext.registerModule(SarifModule.class);
bindingContext.newSerializer(Format.JSON, Sarif.class)
.disableFeature(SerializationFeature.SERIALIZE_ROOT)
@@ -428,7 +466,8 @@ public List generateResults(@NonNull URI output) throws IOException {
assert constraint != null;
ConstraintRuleRecord rule = getRuleRecord(constraint);
- @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") Result result = new Result();
+ @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
+ Result result = new Result();
String id = constraint.getId();
if (id != null) {
diff --git a/databind-metaschema/src/test/java/gov/nist/secauto/metaschema/modules/sarif/SarifValidationHandlerTest.java b/databind-metaschema/src/test/java/gov/nist/secauto/metaschema/modules/sarif/SarifValidationHandlerTest.java
index 9dce9a8d1..76b3488ac 100644
--- a/databind-metaschema/src/test/java/gov/nist/secauto/metaschema/modules/sarif/SarifValidationHandlerTest.java
+++ b/databind-metaschema/src/test/java/gov/nist/secauto/metaschema/modules/sarif/SarifValidationHandlerTest.java
@@ -15,6 +15,7 @@
import gov.nist.secauto.metaschema.core.model.validation.IValidationFinding;
import gov.nist.secauto.metaschema.core.util.IVersionInfo;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
+import gov.nist.secauto.metaschema.databind.IBindingContext;
import org.jmock.Expectations;
import org.jmock.junit5.JUnit5Mockery;
@@ -110,7 +111,7 @@ void testValid() throws IOException {
// no need to cleanup this file, since it is created in the target directory
Path sarifFile = ObjectUtils.requireNonNull(Paths.get("target/test.sarif"));
- handler.write(sarifFile);
+ handler.write(sarifFile, IBindingContext.newInstance());
Path sarifSchema = Paths.get("modules/sarif/sarif-schema-2.1.0.json");
diff --git a/metaschema-cli/pom.xml b/metaschema-cli/pom.xml
index 2c7a9286c..cd71d3fcc 100644
--- a/metaschema-cli/pom.xml
+++ b/metaschema-cli/pom.xml
@@ -44,16 +44,6 @@
${project.groupId}metaschema-databind-modules
-
-
- com.github.spotbugs
- spotbugs-annotations
- org.apache.logging.log4j
@@ -66,8 +56,7 @@
io.github.hakky54
- consolecaptor
- 1.0.3
+ logcaptortest
diff --git a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/CLI.java b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/CLI.java
index 19b96471e..542b654d5 100644
--- a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/CLI.java
+++ b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/CLI.java
@@ -19,6 +19,9 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * The main entry point for the CLI application.
+ */
@SuppressWarnings("PMD.ShortClassName")
public final class CLI {
/**
diff --git a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/AbstractConvertSubcommand.java b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/AbstractConvertSubcommand.java
index e2ae2c789..5921f4d74 100644
--- a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/AbstractConvertSubcommand.java
+++ b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/AbstractConvertSubcommand.java
@@ -12,7 +12,6 @@
import gov.nist.secauto.metaschema.cli.processor.command.CommandExecutionException;
import gov.nist.secauto.metaschema.cli.processor.command.DefaultExtraArgument;
import gov.nist.secauto.metaschema.cli.processor.command.ExtraArgument;
-import gov.nist.secauto.metaschema.core.model.MetaschemaException;
import gov.nist.secauto.metaschema.core.util.AutoCloser;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
import gov.nist.secauto.metaschema.databind.IBindingContext;
@@ -39,7 +38,7 @@
import edu.umd.cs.findbugs.annotations.NonNull;
/**
- * Used by implementing classes to declare a content conversion command.
+ * Used by implementing classes to provide a content conversion command.
*/
public abstract class AbstractConvertSubcommand
extends AbstractTerminalCommand {
@@ -94,11 +93,8 @@ protected AbstractConversionCommandExecutor(
* Get the binding context to use for data processing.
*
* @return the context
- * @throws MetaschemaException
- * if a Metaschema error occurred
- * @throws IOException
- * if an error occurred while reading data
* @throws CommandExecutionException
+ * if an error occurred getting the binding context
*/
@NonNull
protected abstract IBindingContext getBindingContext() throws CommandExecutionException;
diff --git a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/AbstractValidateContentCommand.java b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/AbstractValidateContentCommand.java
index 782891066..f854b42d6 100644
--- a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/AbstractValidateContentCommand.java
+++ b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/AbstractValidateContentCommand.java
@@ -18,7 +18,6 @@
import gov.nist.secauto.metaschema.core.configuration.IMutableConfiguration;
import gov.nist.secauto.metaschema.core.metapath.MetapathException;
import gov.nist.secauto.metaschema.core.model.IModule;
-import gov.nist.secauto.metaschema.core.model.MetaschemaException;
import gov.nist.secauto.metaschema.core.model.constraint.IConstraintSet;
import gov.nist.secauto.metaschema.core.model.constraint.ValidationFeature;
import gov.nist.secauto.metaschema.core.model.validation.AggregateValidationResult;
@@ -47,7 +46,11 @@
import java.util.Set;
import edu.umd.cs.findbugs.annotations.NonNull;
+import edu.umd.cs.findbugs.annotations.Nullable;
+/**
+ * Used by implementing classes to provide a content validation command.
+ */
public abstract class AbstractValidateContentCommand
extends AbstractTerminalCommand {
private static final Logger LOGGER = LogManager.getLogger(AbstractValidateContentCommand.class);
@@ -113,6 +116,9 @@ public List getExtraArguments() {
return EXTRA_ARGUMENTS;
}
+ /**
+ * Drives the validation execution.
+ */
protected abstract class AbstractValidationCommandExecutor
extends AbstractCommandExecutor {
@@ -136,27 +142,59 @@ public AbstractValidationCommandExecutor(
* @param constraintSets
* the constraints to configure in the resulting binding context
* @return the context
- * @throws MetaschemaException
- * if a Metaschema error occurred
- * @throws IOException
- * if an error occurred while reading data
+ * @throws CommandExecutionException
+ * if a error occurred while getting the binding context
*/
@NonNull
protected abstract IBindingContext getBindingContext(@NonNull Set constraintSets)
throws CommandExecutionException;
+ /**
+ * Get the module to use for validation.
+ *
+ * This module is used to generate schemas and as a source of built-in
+ * constraints.
+ *
+ * @param commandLine
+ * the provided command line argument information
+ * @param bindingContext
+ * the context used to access Metaschema module information based on
+ * Java class bindings
+ * @return the loaded Metaschema module
+ * @throws CommandExecutionException
+ * if an error occurred while loading the module
+ */
@NonNull
protected abstract IModule getModule(
@NonNull CommandLine commandLine,
@NonNull IBindingContext bindingContext)
throws CommandExecutionException;
+ /**
+ * Get the schema validation implementation requested based on the provided
+ * command line arguments.
+ *
+ * It is typical for this call to result in the dynamic generation of a schema
+ * to use for validation.
+ *
+ * @param module
+ * the Metaschema module to generate the schema from
+ * @param commandLine
+ * the provided command line argument information
+ * @param bindingContext
+ * the context used to access Metaschema module information based on
+ * Java class bindings
+ * @return the provider
+ */
@NonNull
protected abstract ISchemaValidationProvider getSchemaValidationProvider(
@NonNull IModule module,
@NonNull CommandLine commandLine,
@NonNull IBindingContext bindingContext);
+ /**
+ * Execute the validation operation.
+ */
@SuppressWarnings("PMD.OnlyOneReturn") // readability
@Override
public void execute() throws CommandExecutionException {
@@ -168,40 +206,63 @@ public void execute() throws CommandExecutionException {
CONSTRAINTS_OPTION,
currentWorkingDirectory);
- IBindingContext bindingContext = getBindingContext(constraintSets);
- IBoundLoader loader = bindingContext.newBoundLoader();
-
List extraArgs = cmdLine.getArgList();
URI source = MetaschemaCommands.handleSource(
ObjectUtils.requireNonNull(extraArgs.get(0)),
currentWorkingDirectory);
+ IBindingContext bindingContext = getBindingContext(constraintSets);
+ IBoundLoader loader = bindingContext.newBoundLoader();
Format asFormat = MetaschemaCommands.determineSourceFormat(
cmdLine,
MetaschemaCommands.AS_FORMAT_OPTION,
loader,
source);
- if (LOGGER.isInfoEnabled()) {
- LOGGER.info("Validating '{}' as {}.", source, asFormat.name());
+ IValidationResult validationResult = validate(source, asFormat, cmdLine, bindingContext);
+ handleOutput(source, validationResult, cmdLine, bindingContext);
+
+ if (validationResult == null || validationResult.isPassing()) {
+ if (LOGGER.isInfoEnabled()) {
+ LOGGER.info("The file '{}' is valid.", source);
+ }
+ } else if (LOGGER.isErrorEnabled()) {
+ LOGGER.error("The file '{}' is invalid.", source);
}
- IMutableConfiguration> configuration = new DefaultConfiguration<>();
- if (cmdLine.hasOption(SARIF_OUTPUT_FILE_OPTION) && cmdLine.hasOption(SARIF_INCLUDE_PASS_OPTION)) {
- configuration.enableFeature(ValidationFeature.VALIDATE_GENERATE_PASS_FINDINGS);
+ if (validationResult != null && !validationResult.isPassing()) {
+ throw new CommandExecutionException(ExitCode.FAIL);
+ }
+ }
+
+ @SuppressWarnings("PMD.CyclomaticComplexity")
+ @Nullable
+ private IValidationResult validate(
+ @NonNull URI source,
+ @NonNull Format asFormat,
+ @NonNull CommandLine commandLine,
+ @NonNull IBindingContext bindingContext) throws CommandExecutionException {
+
+ if (LOGGER.isInfoEnabled()) {
+ LOGGER.info("Validating '{}' as {}.", source, asFormat.name());
}
IValidationResult validationResult = null;
try {
- IModule module = bindingContext.registerModule(getModule(getCommandLine(), bindingContext));
- if (!cmdLine.hasOption(NO_SCHEMA_VALIDATION_OPTION)) {
+ IModule module = bindingContext.registerModule(getModule(commandLine, bindingContext));
+ if (!commandLine.hasOption(NO_SCHEMA_VALIDATION_OPTION)) {
// perform schema validation
- validationResult = getSchemaValidationProvider(module, getCommandLine(), bindingContext)
+ validationResult = getSchemaValidationProvider(module, commandLine, bindingContext)
.validateWithSchema(source, asFormat, bindingContext);
}
- if (!cmdLine.hasOption(NO_CONSTRAINT_VALIDATION_OPTION)) {
+ if (!commandLine.hasOption(NO_CONSTRAINT_VALIDATION_OPTION)) {
+ IMutableConfiguration> configuration = new DefaultConfiguration<>();
+ if (commandLine.hasOption(SARIF_OUTPUT_FILE_OPTION) && commandLine.hasOption(SARIF_INCLUDE_PASS_OPTION)) {
+ configuration.enableFeature(ValidationFeature.VALIDATE_GENERATE_PASS_FINDINGS);
+ }
+
// perform constraint validation
IValidationResult constraintValidationResult = bindingContext.validateWithConstraints(source, configuration);
validationResult = validationResult == null
@@ -223,9 +284,16 @@ public void execute() throws CommandExecutionException {
} catch (MetapathException ex) {
throw new CommandExecutionException(ExitCode.PROCESSING_ERROR, ex.getLocalizedMessage(), ex);
}
+ return validationResult;
+ }
- if (cmdLine.hasOption(SARIF_OUTPUT_FILE_OPTION) && LOGGER.isInfoEnabled()) {
- Path sarifFile = ObjectUtils.notNull(Paths.get(cmdLine.getOptionValue(SARIF_OUTPUT_FILE_OPTION)));
+ private void handleOutput(
+ @NonNull URI source,
+ @Nullable IValidationResult validationResult,
+ @NonNull CommandLine commandLine,
+ @NonNull IBindingContext bindingContext) throws CommandExecutionException {
+ if (commandLine.hasOption(SARIF_OUTPUT_FILE_OPTION) && LOGGER.isInfoEnabled()) {
+ Path sarifFile = ObjectUtils.notNull(Paths.get(commandLine.getOptionValue(SARIF_OUTPUT_FILE_OPTION)));
IVersionInfo version
= getCallingContext().getCLIProcessor().getVersionInfos().get(CLIProcessor.COMMAND_VERSION);
@@ -235,7 +303,7 @@ public void execute() throws CommandExecutionException {
if (validationResult != null) {
sarifHandler.addFindings(validationResult.getFindings());
}
- sarifHandler.write(sarifFile);
+ sarifHandler.write(sarifFile, bindingContext);
} catch (IOException ex) {
throw new CommandExecutionException(ExitCode.IO_ERROR, ex.getLocalizedMessage(), ex);
}
@@ -244,17 +312,6 @@ public void execute() throws CommandExecutionException {
LoggingValidationHandler.instance().handleResults(validationResult);
}
- if (validationResult == null || validationResult.isPassing()) {
- if (LOGGER.isInfoEnabled()) {
- LOGGER.info("The file '{}' is valid.", source);
- }
- } else if (LOGGER.isErrorEnabled()) {
- LOGGER.error("The file '{}' is invalid.", source);
- }
-
- if (validationResult != null && !validationResult.isPassing()) {
- throw new CommandExecutionException(ExitCode.FAIL);
- }
}
}
}
diff --git a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/ConvertContentUsingModuleCommand.java b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/ConvertContentUsingModuleCommand.java
index 632d393d2..4b6bdc298 100644
--- a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/ConvertContentUsingModuleCommand.java
+++ b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/ConvertContentUsingModuleCommand.java
@@ -35,7 +35,11 @@
import edu.umd.cs.findbugs.annotations.NonNull;
-public class ConvertContentUsingModuleCommand
+/**
+ * This command implementation supports the conversion of a content instance
+ * between supported formats based on a provided Metaschema module.
+ */
+class ConvertContentUsingModuleCommand
extends AbstractConvertSubcommand {
@NonNull
private static final String COMMAND = "convert";
@@ -80,7 +84,7 @@ private CommandExecutor(
protected IBindingContext getBindingContext() throws CommandExecutionException {
IBindingContext retval = MetaschemaCommands.newBindingContextWithDynamicCompilation();
- IModule module = MetaschemaCommands.handleModule(
+ IModule module = MetaschemaCommands.loadModule(
getCommandLine(),
MetaschemaCommands.METASCHEMA_REQUIRED_OPTION,
ObjectUtils.notNull(getCurrentWorkingDirectory().toUri()),
diff --git a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/GenerateDiagramCommand.java b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/GenerateDiagramCommand.java
index 267a413f5..513265be8 100644
--- a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/GenerateDiagramCommand.java
+++ b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/GenerateDiagramCommand.java
@@ -38,7 +38,11 @@
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-public class GenerateDiagramCommand
+/**
+ * This command implementation supports generation of a diagram depicting the
+ * objects and relationships within a provided Metaschema module.
+ */
+class GenerateDiagramCommand
extends AbstractTerminalCommand {
private static final Logger LOGGER = LogManager.getLogger(GenerateDiagramCommand.class);
@@ -66,8 +70,7 @@ public String getDescription() {
@SuppressWarnings("null")
@Override
public Collection extends Option> gatherOptions() {
- return List.of(
- MetaschemaCommands.OVERWRITE_OPTION);
+ return List.of(MetaschemaCommands.OVERWRITE_OPTION);
}
@Override
@@ -87,7 +90,8 @@ public ICommandExecutor newExecutor(CallingContext callingContext, CommandLine c
* information about the calling context
* @param cmdLine
* the parsed command line details
- * @return the execution result
+ * @throws CommandExecutionException
+ * if an error occurred while executing the command
*/
@SuppressWarnings({
"PMD.OnlyOneReturn", // readability
@@ -119,7 +123,7 @@ protected void executeCommand(
ex.getLocalizedMessage()),
ex);
}
- IModule module = MetaschemaCommands.handleModule(moduleUri, bindingContext);
+ IModule module = MetaschemaCommands.loadModule(moduleUri, bindingContext);
if (destination == null) {
Writer stringWriter = new StringWriter();
diff --git a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/GenerateSchemaCommand.java b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/GenerateSchemaCommand.java
index d05e780cd..ba91e4b69 100644
--- a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/GenerateSchemaCommand.java
+++ b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/GenerateSchemaCommand.java
@@ -7,9 +7,6 @@
import gov.nist.secauto.metaschema.cli.processor.CLIProcessor.CallingContext;
import gov.nist.secauto.metaschema.cli.processor.ExitCode;
-import gov.nist.secauto.metaschema.cli.processor.ExitStatus;
-import gov.nist.secauto.metaschema.cli.processor.InvalidArgumentException;
-import gov.nist.secauto.metaschema.cli.processor.OptionUtils;
import gov.nist.secauto.metaschema.cli.processor.command.AbstractTerminalCommand;
import gov.nist.secauto.metaschema.cli.processor.command.CommandExecutionException;
import gov.nist.secauto.metaschema.cli.processor.command.DefaultExtraArgument;
@@ -34,22 +31,26 @@
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
import java.nio.file.Path;
-import java.nio.file.Paths;
import java.util.Collection;
import java.util.List;
import edu.umd.cs.findbugs.annotations.NonNull;
-public class GenerateSchemaCommand
+/**
+ * This command implementation supports generation of schemas in a variety of
+ * formats based on a provided Metaschema module.
+ */
+class GenerateSchemaCommand
extends AbstractTerminalCommand {
private static final Logger LOGGER = LogManager.getLogger(GenerateSchemaCommand.class);
@NonNull
private static final String COMMAND = "generate-schema";
@NonNull
- private static final List EXTRA_ARGUMENTS;
+ private static final List EXTRA_ARGUMENTS = ObjectUtils.notNull(List.of(
+ new DefaultExtraArgument("metaschema-module-file-or-URL", true),
+ new DefaultExtraArgument("destination-schema-file", false)));
private static final Option INLINE_TYPES_OPTION = ObjectUtils.notNull(
Option.builder()
@@ -57,12 +58,6 @@ public class GenerateSchemaCommand
.desc("definitions declared inline will be generated as inline types")
.build());
- static {
- EXTRA_ARGUMENTS = ObjectUtils.notNull(List.of(
- new DefaultExtraArgument("metaschema-module-file-or-URL", true),
- new DefaultExtraArgument("destination-schema-file", false)));
- }
-
@Override
public String getName() {
return COMMAND;
@@ -87,75 +82,37 @@ public List getExtraArguments() {
return EXTRA_ARGUMENTS;
}
- @SuppressWarnings("PMD.PreserveStackTrace") // intended
- @Override
- public void validateOptions(CallingContext callingContext, CommandLine cmdLine) throws InvalidArgumentException {
- List extraArgs = cmdLine.getArgList();
- if (extraArgs.isEmpty() || extraArgs.size() > 2) {
- throw new InvalidArgumentException("Illegal number of arguments.");
- }
- }
-
@Override
public ICommandExecutor newExecutor(CallingContext callingContext, CommandLine cmdLine) {
return ICommandExecutor.using(callingContext, cmdLine, this::executeCommand);
}
/**
- * Called to execute the schema generation.
+ * Execute the schema generation operation.
*
* @param callingContext
* the context information for the execution
* @param cmdLine
* the parsed command line details
- * @return the execution result
* @throws CommandExecutionException
+ * if an error occurred while determining the source format
*/
@SuppressWarnings({
- "PMD.OnlyOneReturn" // readability
+ "PMD.OnlyOneReturn", // readability
+ "PMD.CyclomaticComplexity"
})
- protected ExitStatus executeCommand(
+ protected void executeCommand(
@NonNull CallingContext callingContext,
@NonNull CommandLine cmdLine) throws CommandExecutionException {
List extraArgs = cmdLine.getArgList();
- Path destination = null;
- if (extraArgs.size() > 1) {
- destination = Paths.get(extraArgs.get(1)).toAbsolutePath();
- }
+ Path destination = extraArgs.size() > 1
+ ? MetaschemaCommands.handleDestination(
+ ObjectUtils.requireNonNull(extraArgs.get(1)),
+ cmdLine)
+ : null;
- if (destination != null) {
- if (Files.exists(destination)) {
- if (!cmdLine.hasOption(MetaschemaCommands.OVERWRITE_OPTION)) {
- return ExitCode.INVALID_ARGUMENTS.exitMessage( // NOPMD readability
- String.format("The provided destination '%s' already exists and the '%s' option was not provided.",
- destination,
- OptionUtils.toArgument(MetaschemaCommands.OVERWRITE_OPTION)));
- }
- if (!Files.isWritable(destination)) {
- return ExitCode.IO_ERROR.exitMessage( // NOPMD readability
- "The provided destination '" + destination + "' is not writable.");
- }
- } else {
- Path parent = destination.getParent();
- if (parent != null) {
- try {
- Files.createDirectories(parent);
- } catch (IOException ex) {
- return ExitCode.INVALID_TARGET.exit().withThrowable(ex); // NOPMD readability
- }
- }
- }
- }
-
- SchemaFormat asFormat;
- try {
- asFormat = MetaschemaCommands.getSchemaFormat(cmdLine, MetaschemaCommands.AS_SCHEMA_FORMAT_OPTION);
- } catch (InvalidArgumentException ex) {
- return ExitCode.INVALID_ARGUMENTS
- .exitMessage(ex.getLocalizedMessage())
- .withThrowable(ex);
- }
+ SchemaFormat asFormat = MetaschemaCommands.getSchemaFormat(cmdLine, MetaschemaCommands.AS_SCHEMA_FORMAT_OPTION);
IMutableConfiguration> configuration = new DefaultConfiguration<>();
if (cmdLine.hasOption(INLINE_TYPES_OPTION)) {
@@ -168,7 +125,7 @@ protected ExitStatus executeCommand(
}
IBindingContext bindingContext = MetaschemaCommands.newBindingContextWithDynamicCompilation();
- IModule module = MetaschemaCommands.handleModule(
+ IModule module = MetaschemaCommands.loadModule(
ObjectUtils.requireNonNull(extraArgs.get(0)),
ObjectUtils.notNull(getCurrentWorkingDirectory().toUri()),
bindingContext);
@@ -191,11 +148,10 @@ protected ExitStatus executeCommand(
ISchemaGenerator.generateSchema(module, destination, asFormat, configuration);
}
} catch (IOException ex) {
- return ExitCode.PROCESSING_ERROR.exit().withThrowable(ex); // NOPMD readability
+ throw new CommandExecutionException(ExitCode.PROCESSING_ERROR, ex);
}
if (destination != null && LOGGER.isInfoEnabled()) {
LOGGER.info("Generated {} schema file: {}", asFormat.toString(), destination);
}
- return ExitCode.OK.exit();
}
}
diff --git a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/MetaschemaCommands.java b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/MetaschemaCommands.java
index 88fd6c59f..f009ecf59 100644
--- a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/MetaschemaCommands.java
+++ b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/MetaschemaCommands.java
@@ -7,7 +7,6 @@
import gov.nist.secauto.metaschema.cli.commands.metapath.MetapathCommand;
import gov.nist.secauto.metaschema.cli.processor.ExitCode;
-import gov.nist.secauto.metaschema.cli.processor.InvalidArgumentException;
import gov.nist.secauto.metaschema.cli.processor.OptionUtils;
import gov.nist.secauto.metaschema.cli.processor.command.CommandExecutionException;
import gov.nist.secauto.metaschema.cli.processor.command.ICommand;
@@ -18,6 +17,7 @@
import gov.nist.secauto.metaschema.core.model.constraint.IConstraintSet;
import gov.nist.secauto.metaschema.core.util.CollectionUtil;
import gov.nist.secauto.metaschema.core.util.CustomCollectors;
+import gov.nist.secauto.metaschema.core.util.DeleteOnShutdown;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
import gov.nist.secauto.metaschema.core.util.UriUtils;
import gov.nist.secauto.metaschema.databind.IBindingContext;
@@ -44,7 +44,21 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * This class provides a variety of utility methods for processing
+ * Metaschema-related commands.
+ *
+ * These methods handle the errors produced using the
+ * {@link CommandExecutionException}, which will return an exceptional result to
+ * the command line interface (CLI) processor. This approach keeps the command
+ * implementations fairly clean and simple.
+ */
+@SuppressWarnings("PMD.GodClass")
public final class MetaschemaCommands {
+ /**
+ * A list of the Metaschema-related command pathways, for reuse in this and
+ * other CLI applications.
+ */
@NonNull
public static final List COMMANDS = ObjectUtils.notNull(List.of(
new ValidateModuleCommand(),
@@ -54,6 +68,11 @@ public final class MetaschemaCommands {
new ConvertContentUsingModuleCommand(),
new MetapathCommand()));
+ /**
+ * Used by commands to declare a required Metaschema module for processing.
+ *
+ * @since 2.0.0
+ */
@NonNull
public static final Option METASCHEMA_REQUIRED_OPTION = ObjectUtils.notNull(
Option.builder("m")
@@ -63,6 +82,11 @@ public final class MetaschemaCommands {
.desc("metaschema resource")
.numberOfArgs(1)
.build());
+ /**
+ * Used by commands to declare an optional Metaschema module for processing.
+ *
+ * @since 2.0.0
+ */
@NonNull
public static final Option METASCHEMA_OPTIONAL_OPTION = ObjectUtils.notNull(
Option.builder("m")
@@ -71,12 +95,22 @@ public final class MetaschemaCommands {
.desc("metaschema resource")
.numberOfArgs(1)
.build());
+ /**
+ * Used by commands to protect existing files from being overwritten, unless
+ * this option is provided.
+ */
@NonNull
public static final Option OVERWRITE_OPTION = ObjectUtils.notNull(
Option.builder()
.longOpt("overwrite")
.desc("overwrite the destination if it exists")
.build());
+ /**
+ * Used by commands to identify the target format for a content conversion
+ * operation.
+ *
+ * @since 2.0.0
+ */
@NonNull
public static final Option TO_OPTION = ObjectUtils.notNull(
Option.builder()
@@ -88,6 +122,12 @@ public final class MetaschemaCommands {
.collect(CustomCollectors.joiningWithOxfordComma("or")))
.numberOfArgs(1)
.build());
+ /**
+ * Used by commands to identify the source format for a content-related
+ * operation.
+ *
+ * @since 2.0.0
+ */
@NonNull
public static final Option AS_FORMAT_OPTION = ObjectUtils.notNull(
Option.builder()
@@ -99,6 +139,12 @@ public final class MetaschemaCommands {
.collect(CustomCollectors.joiningWithOxfordComma("or")))
.numberOfArgs(1)
.build());
+ /**
+ * Used by commands that produce schemas to identify the schema format to
+ * produce.
+ *
+ * @since 2.0.0
+ */
@NonNull
public static final Option AS_SCHEMA_FORMAT_OPTION = ObjectUtils.notNull(
Option.builder()
@@ -124,6 +170,7 @@ public final class MetaschemaCommands {
* @return the absolute URI for the resource
* @throws CommandExecutionException
* if the resulting URI is not a well-formed URI
+ * @since 2.0.0
*/
@NonNull
public static URI handleSource(
@@ -156,6 +203,7 @@ public static URI handleSource(
* @return the absolute URI for the resource
* @throws CommandExecutionException
* if the path exists and cannot be overwritten or is not writable
+ * @since 2.0.0
*/
public static Path handleDestination(
@NonNull String path,
@@ -202,14 +250,15 @@ public static Path handleDestination(
* @return the format
* @throws CommandExecutionException
* if the format option was not provided or was an invalid choice
+ * @since 2.0.0
*/
@SuppressWarnings("PMD.PreserveStackTrace")
@NonNull
public static Format getFormat(
- @NonNull CommandLine cmdLine,
+ @NonNull CommandLine commandLine,
@NonNull Option option) throws CommandExecutionException {
// use the option
- String toFormatText = cmdLine.getOptionValue(option);
+ String toFormatText = commandLine.getOptionValue(option);
if (toFormatText == null) {
throw new CommandExecutionException(
ExitCode.INVALID_ARGUMENTS,
@@ -234,33 +283,81 @@ public static Format getFormat(
}
/**
+ * Parse the command line options to get the selected schema format.
*
- * @param cmdLine
+ * @param commandLine
+ * the provided command line argument information
* @param option
+ * the option specifying the format, which must be present on the
+ * command line
+ * @return the format
+ * @throws CommandExecutionException
+ * if the format option was not provided or was an invalid choice
+ * @since 2.0.0
+ */
+ @SuppressWarnings("PMD.PreserveStackTrace")
+ @NonNull
+ public static SchemaFormat getSchemaFormat(
+ @NonNull CommandLine commandLine,
+ @NonNull Option option) throws CommandExecutionException {
+ // use the option
+ String toFormatText = commandLine.getOptionValue(option);
+ if (toFormatText == null) {
+ throw new CommandExecutionException(
+ ExitCode.INVALID_ARGUMENTS,
+ String.format("Option '%s' not provided.",
+ option.hasLongOpt()
+ ? "--" + option.getLongOpt()
+ : "-" + option.getOpt()));
+ }
+ try {
+ return SchemaFormat.valueOf(toFormatText.toUpperCase(Locale.ROOT));
+ } catch (IllegalArgumentException ex) {
+ throw new CommandExecutionException(
+ ExitCode.INVALID_ARGUMENTS,
+ String.format("Invalid '%s' argument. The schema format must be one of: %s.",
+ option.hasLongOpt()
+ ? "--" + option.getLongOpt()
+ : "-" + option.getOpt(),
+ Arrays.stream(SchemaFormat.values())
+ .map(Enum::name)
+ .collect(CustomCollectors.joiningWithOxfordComma("or"))),
+ ex);
+ }
+ }
+
+ /**
+ * Detect the source format for content identified using the provided option.
+ *
+ * This method will first check if the source format is explicitly declared on
+ * the command line. If so, this format will be returned.
+ *
+ * If not, then the content will be analyzed to determine the format.
+ *
+ * @param commandLine
+ * the provided command line argument information
+ * @param option
+ * the option specifying the format, which must be present on the
+ * command line
* @param loader
+ * the content loader to use to load the content instance
* @param resource
- * @return
- * @throws InvalidArgumentException
- * if the option is not a supported format
- * @throws FileNotFoundException
- * if the URI is a file that was not found
- * @throws IOException
- * if there was an error reading the file to determine the format of
- * the file
- * @throws IllegalArgumentException
- * if the format of the source file was not recognized
+ * the resource to load
+ * @return the identified content format
+ * @throws CommandExecutionException
+ * if an error occurred while determining the source format
* @since 2.0.0
*/
@SuppressWarnings({ "PMD.PreserveStackTrace", "PMD.OnlyOneReturn" })
@NonNull
public static Format determineSourceFormat(
- @NonNull CommandLine cmdLine,
+ @NonNull CommandLine commandLine,
@NonNull Option option,
@NonNull IBoundLoader loader,
@NonNull URI resource) throws CommandExecutionException {
- if (cmdLine.hasOption(option)) {
+ if (commandLine.hasOption(option)) {
// use the option
- return getFormat(cmdLine, option);
+ return getFormat(commandLine, option);
}
// attempt to determine the format
@@ -284,11 +381,29 @@ public static Format determineSourceFormat(
}
}
+ /**
+ * Load a Metaschema module based on the provided command line option.
+ *
+ * @param commandLine
+ * the provided command line argument information
+ * @param option
+ * the option specifying the module to load, which must be present on
+ * the command line
+ * @param currentWorkingDirectory
+ * the URI of the current working directory
+ * @param bindingContext
+ * the context used to access Metaschema module information based on
+ * Java class bindings
+ * @return the loaded module
+ * @throws CommandExecutionException
+ * if an error occurred while loading the module
+ * @since 2.0.0
+ */
@NonNull
- public static IModule handleModule(
+ public static IModule loadModule(
@NonNull CommandLine commandLine,
@NonNull Option option,
- @NonNull URI cwd,
+ @NonNull URI currentWorkingDirectory,
@NonNull IBindingContext bindingContext) throws CommandExecutionException {
String moduleName = commandLine.getOptionValue(option);
if (moduleName == null) {
@@ -302,7 +417,7 @@ public static IModule handleModule(
URI moduleUri;
try {
- moduleUri = UriUtils.toUri(moduleName, cwd);
+ moduleUri = UriUtils.toUri(moduleName, currentWorkingDirectory);
} catch (URISyntaxException ex) {
throw new CommandExecutionException(
ExitCode.INVALID_ARGUMENTS,
@@ -311,11 +426,29 @@ public static IModule handleModule(
ex.getLocalizedMessage()),
ex);
}
- return handleModule(moduleUri, bindingContext);
+ return loadModule(moduleUri, bindingContext);
}
+ /**
+ * Load a Metaschema module from the provided relative resource path.
+ *
+ * This method will resolve the provided resource against the current working
+ * directory to create an absolute URI.
+ *
+ * @param moduleResource
+ * the relative path to the module resource to load
+ * @param currentWorkingDirectory
+ * the URI of the current working directory
+ * @param bindingContext
+ * the context used to access Metaschema module information based on
+ * Java class bindings
+ * @return the loaded module
+ * @throws CommandExecutionException
+ * if an error occurred while loading the module
+ * @since 2.0.0
+ */
@NonNull
- public static IModule handleModule(
+ public static IModule loadModule(
@NonNull String moduleResource,
@NonNull URI currentWorkingDirectory,
@NonNull IBindingContext bindingContext) throws CommandExecutionException {
@@ -323,7 +456,7 @@ public static IModule handleModule(
URI moduleUri = getResourceUri(
moduleResource,
currentWorkingDirectory);
- return handleModule(moduleUri, bindingContext);
+ return loadModule(moduleUri, bindingContext);
} catch (URISyntaxException ex) {
throw new CommandExecutionException(
ExitCode.INVALID_ARGUMENTS,
@@ -334,10 +467,24 @@ public static IModule handleModule(
}
}
+ /**
+ * Load a Metaschema module from the provided resource path.
+ *
+ * @param moduleResource
+ * the absolute path to the module resource to load
+ * @param bindingContext
+ * the context used to access Metaschema module information based on
+ * Java class bindings
+ * @return the loaded module
+ * @throws CommandExecutionException
+ * if an error occurred while loading the module
+ * @since 2.0.0
+ */
@NonNull
- public static IModule handleModule(
+ public static IModule loadModule(
@NonNull URI moduleResource,
@NonNull IBindingContext bindingContext) throws CommandExecutionException {
+ // TODO: ensure the resource URI is absolute
try {
IBindingModuleLoader loader = bindingContext.newModuleLoader();
loader.allowEntityResolution();
@@ -352,7 +499,7 @@ public static IModule handleModule(
*
* @param location
* the resource location
- * @param cwd
+ * @param currentWorkingDirectory
* the URI of the current working directory
* @return the resolved URI
* @throws URISyntaxException
@@ -361,24 +508,40 @@ public static IModule handleModule(
@NonNull
public static URI getResourceUri(
@NonNull String location,
- @NonNull URI cwd) throws URISyntaxException {
- return UriUtils.toUri(location, cwd);
+ @NonNull URI currentWorkingDirectory) throws URISyntaxException {
+ return UriUtils.toUri(location, currentWorkingDirectory);
}
+ /**
+ * Load a set of external Metaschema module constraints based on the provided
+ * command line option.
+ *
+ * @param commandLine
+ * the provided command line argument information
+ * @param option
+ * the option specifying the constraints to load, which must be present
+ * on the command line
+ * @param currentWorkingDirectory
+ * the URI of the current working directory
+ * @return the set of loaded constraints
+ * @throws CommandExecutionException
+ * if an error occurred while loading the module
+ * @since 2.0.0
+ */
@NonNull
public static Set loadConstraintSets(
- @NonNull CommandLine cmdLine,
+ @NonNull CommandLine commandLine,
@NonNull Option option,
- @NonNull URI cwd) throws CommandExecutionException {
+ @NonNull URI currentWorkingDirectory) throws CommandExecutionException {
Set constraintSets;
- if (cmdLine.hasOption(option)) {
+ if (commandLine.hasOption(option)) {
IConstraintLoader constraintLoader = IBindingContext.getConstraintLoader();
constraintSets = new LinkedHashSet<>();
- String[] args = cmdLine.getOptionValues(option);
+ String[] args = commandLine.getOptionValues(option);
for (String arg : args) {
assert arg != null;
try {
- URI constraintUri = ObjectUtils.requireNonNull(UriUtils.toUri(arg, cwd));
+ URI constraintUri = ObjectUtils.requireNonNull(UriUtils.toUri(arg, currentWorkingDirectory));
constraintSets.addAll(constraintLoader.load(constraintUri));
} catch (URISyntaxException | IOException | MetaschemaException | MetapathException ex) {
throw new CommandExecutionException(
@@ -395,24 +558,52 @@ public static Set loadConstraintSets(
return constraintSets;
}
+ /**
+ * Create a temporary directory for ephemeral files that will be deleted on
+ * shutdown.
+ *
+ * @return the temp directory path
+ * @throws IOException
+ * if an error occurred while creating the temporary directory
+ */
@NonNull
public static Path newTempDir() throws IOException {
Path retval = Files.createTempDirectory("metaschema-cli-");
- retval.toFile().deleteOnExit();
- return retval;
+ DeleteOnShutdown.register(retval);
+ return ObjectUtils.notNull(retval);
}
+ /**
+ * Create a new {@link IBindingContext} that is configured for dynamic
+ * compilation.
+ *
+ * @return the binding context
+ * @throws CommandExecutionException
+ * if an error occurred while creating the binding context
+ * @since 2.0.0
+ */
@NonNull
public static IBindingContext newBindingContextWithDynamicCompilation() throws CommandExecutionException {
return newBindingContextWithDynamicCompilation(CollectionUtil.emptySet());
}
+ /**
+ * Create a new {@link IBindingContext} that is configured for dynamic
+ * compilation and to use the provided constraints.
+ *
+ * @param constraintSets
+ * the Metaschema module constraints to dynamicly bind to loaded
+ * modules
+ * @return the binding context
+ * @throws CommandExecutionException
+ * if an error occurred while creating the binding context
+ * @since 2.0.0
+ */
@NonNull
public static IBindingContext newBindingContextWithDynamicCompilation(@NonNull Set constraintSets)
throws CommandExecutionException {
try {
Path tempDir = newTempDir();
- tempDir.toFile().deleteOnExit();
return IBindingContext.builder()
.compilePath(tempDir)
.constraintSet(constraintSets)
@@ -424,34 +615,6 @@ public static IBindingContext newBindingContextWithDynamicCompilation(@NonNull S
}
}
- @SuppressWarnings("PMD.PreserveStackTrace")
- @NonNull
- public static SchemaFormat getSchemaFormat(
- @NonNull CommandLine cmdLine,
- @NonNull Option option) throws InvalidArgumentException {
- // use the option
- String toFormatText = cmdLine.getOptionValue(option);
- if (toFormatText == null) {
- throw new IllegalArgumentException(
- String.format("Option '%s' not provided.",
- option.hasLongOpt()
- ? "--" + option.getLongOpt()
- : "-" + option.getOpt()));
- }
- try {
- return SchemaFormat.valueOf(toFormatText.toUpperCase(Locale.ROOT));
- } catch (IllegalArgumentException ex) {
- throw new InvalidArgumentException(
- String.format("Invalid '%s' argument. The schema format must be one of: %s.",
- option.hasLongOpt()
- ? "--" + option.getLongOpt()
- : "-" + option.getOpt(),
- Arrays.stream(SchemaFormat.values())
- .map(Enum::name)
- .collect(CustomCollectors.joiningWithOxfordComma("or"))));
- }
- }
-
private MetaschemaCommands() {
// disable construction
}
diff --git a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/ValidateContentUsingModuleCommand.java b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/ValidateContentUsingModuleCommand.java
index 87b091a42..300c3413d 100644
--- a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/ValidateContentUsingModuleCommand.java
+++ b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/ValidateContentUsingModuleCommand.java
@@ -42,7 +42,11 @@
import edu.umd.cs.findbugs.annotations.NonNull;
-public class ValidateContentUsingModuleCommand
+/**
+ * This command implementation supports validation of a content instance based
+ * on a provided Metaschema module.
+ */
+class ValidateContentUsingModuleCommand
extends AbstractValidateContentCommand {
@NonNull
private static final String COMMAND = "validate-content";
@@ -92,7 +96,7 @@ protected IBindingContext getBindingContext(@NonNull Set constra
protected IModule getModule(
CommandLine commandLine,
IBindingContext bindingContext) throws CommandExecutionException {
- return MetaschemaCommands.handleModule(
+ return MetaschemaCommands.loadModule(
commandLine,
MetaschemaCommands.METASCHEMA_REQUIRED_OPTION,
ObjectUtils.notNull(getCurrentWorkingDirectory().toUri()),
diff --git a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/ValidateModuleCommand.java b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/ValidateModuleCommand.java
index cecd2f474..22400c6bc 100644
--- a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/ValidateModuleCommand.java
+++ b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/ValidateModuleCommand.java
@@ -38,7 +38,10 @@
import edu.umd.cs.findbugs.annotations.NonNull;
import nl.talsmasoftware.lazy4j.Lazy;
-public class ValidateModuleCommand
+/**
+ * This command implementation supports validation a Metaschema module.
+ */
+class ValidateModuleCommand
extends AbstractValidateContentCommand {
@NonNull
private static final String COMMAND = "validate";
@@ -55,14 +58,14 @@ public String getDescription() {
@Override
public ICommandExecutor newExecutor(CallingContext callingContext, CommandLine commandLine) {
- return new ValidateModuleCommandExecutor(callingContext, commandLine);
+ return new CommandExecutor(callingContext, commandLine);
}
- private final class ValidateModuleCommandExecutor
+ private final class CommandExecutor
extends AbstractValidationCommandExecutor {
private final Lazy validationProvider = Lazy.lazy(ValidationProvider::new);
- private ValidateModuleCommandExecutor(
+ private CommandExecutor(
@NonNull CallingContext callingContext,
@NonNull CommandLine commandLine) {
super(callingContext, commandLine);
diff --git a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/metapath/EvaluateMetapathCommand.java b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/metapath/EvaluateMetapathCommand.java
index 2c1f9b4e5..5ab8be68c 100644
--- a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/metapath/EvaluateMetapathCommand.java
+++ b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/metapath/EvaluateMetapathCommand.java
@@ -8,7 +8,6 @@
import gov.nist.secauto.metaschema.cli.commands.MetaschemaCommands;
import gov.nist.secauto.metaschema.cli.processor.CLIProcessor.CallingContext;
import gov.nist.secauto.metaschema.cli.processor.ExitCode;
-import gov.nist.secauto.metaschema.cli.processor.InvalidArgumentException;
import gov.nist.secauto.metaschema.cli.processor.command.AbstractTerminalCommand;
import gov.nist.secauto.metaschema.cli.processor.command.CommandExecutionException;
import gov.nist.secauto.metaschema.cli.processor.command.ExtraArgument;
@@ -44,7 +43,21 @@
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-public class EvaluateMetapathCommand
+/**
+ * This command implementation executes a Metapath query.
+ *
+ * The query is executed using one of the following configurations:
+ *
+ *
module and content: on a content instance parsed using a provided
+ * Metaschema module,
+ *
module-only: against the Metaschema module itself if no content
+ * instance is provided, or
+ *
without content or module: if both a module and content are
+ * omitted then the execution will be limited to operations that do not act on
+ * content.
+ *
+ */
+class EvaluateMetapathCommand
extends AbstractTerminalCommand {
private static final Logger LOGGER = LogManager.getLogger(EvaluateMetapathCommand.class);
@@ -91,14 +104,6 @@ public List getExtraArguments() {
return CollectionUtil.emptyList();
}
- @Override
- public void validateOptions(CallingContext callingContext, CommandLine cmdLine) throws InvalidArgumentException {
- List extraArgs = cmdLine.getArgList();
- if (!extraArgs.isEmpty()) {
- throw new InvalidArgumentException("Illegal number of extra arguments.");
- }
- }
-
@Override
public ICommandExecutor newExecutor(CallingContext callingContext, CommandLine cmdLine) {
return ICommandExecutor.using(callingContext, cmdLine, this::executeCommand);
@@ -106,7 +111,10 @@ public ICommandExecutor newExecutor(CallingContext callingContext, CommandLine c
@SuppressWarnings({
"PMD.OnlyOneReturn", // readability
- "PMD.AvoidCatchingGenericException"
+ "PMD.AvoidCatchingGenericException",
+ "PMD.NPathComplexity",
+ "PMD.CognitiveComplexity",
+ "PMD.CyclomaticComplexity"
})
@SuppressFBWarnings(value = "REC_CATCH_EXCEPTION",
justification = "Catching generic exception for CLI error handling")
@@ -119,12 +127,11 @@ private void executeCommand(
if (cmdLine.hasOption(MetaschemaCommands.METASCHEMA_OPTIONAL_OPTION)) {
IBindingContext bindingContext = MetaschemaCommands.newBindingContextWithDynamicCompilation();
- module = MetaschemaCommands.handleModule(
+ module = bindingContext.registerModule(MetaschemaCommands.loadModule(
cmdLine,
MetaschemaCommands.METASCHEMA_OPTIONAL_OPTION,
ObjectUtils.notNull(getCurrentWorkingDirectory().toUri()),
- bindingContext);
- bindingContext.registerModule(module);
+ bindingContext));
// determine if the query is evaluated against the module or the instance
if (cmdLine.hasOption(CONTENT_OPTION)) {
@@ -158,16 +165,18 @@ private void executeCommand(
ex);
}
} else {
+ // evaluate against the module
item = INodeItemFactory.instance().newModuleNodeItem(module);
}
} else if (cmdLine.hasOption(CONTENT_OPTION)) {
// content provided, but no module; require module
- String contentLocation = ObjectUtils.requireNonNull(cmdLine.getOptionValue(CONTENT_OPTION));
throw new CommandExecutionException(
ExitCode.INVALID_ARGUMENTS,
- String.format("Must use '%s' to specify the Metaschema module.", CONTENT_OPTION.getArgName()));
+ String.format("Must use '%s' to specify the Metaschema module.",
+ CONTENT_OPTION.getArgName()));
}
+ // now setup to evaluate the metapath
StaticContext.Builder builder = StaticContext.builder();
if (module != null) {
builder.defaultModelNamespace(module.getXmlNamespace());
@@ -186,6 +195,7 @@ private void executeCommand(
MetapathExpression compiledMetapath = MetapathExpression.compile(expression, staticContext);
ISequence> sequence = compiledMetapath.evaluate(item, new DynamicContext(staticContext));
+ // handle the metapath results
try (Writer stringWriter = new StringWriter()) {
try (PrintWriter writer = new PrintWriter(stringWriter)) {
try (IItemWriter itemWriter = new DefaultItemWriter(writer)) {
diff --git a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/metapath/ListFunctionsSubcommand.java b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/metapath/ListFunctionsSubcommand.java
index cc597da12..2537725f8 100644
--- a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/metapath/ListFunctionsSubcommand.java
+++ b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/metapath/ListFunctionsSubcommand.java
@@ -28,7 +28,11 @@
import edu.umd.cs.findbugs.annotations.NonNull;
-public class ListFunctionsSubcommand
+/**
+ * This command list the Metapath functions currently provided by the Metaschema
+ * runtime.
+ */
+class ListFunctionsSubcommand
extends AbstractTerminalCommand {
private static final Logger LOGGER = LogManager.getLogger(ListFunctionsSubcommand.class);
@@ -61,7 +65,8 @@ public ICommandExecutor newExecutor(CallingContext callingContext, CommandLine c
*/
@SuppressWarnings({
"PMD.OnlyOneReturn", // readability
- "PMD.AvoidInstantiatingObjectsInLoops"
+ "PMD.AvoidInstantiatingObjectsInLoops",
+ "PMD.CognitiveComplexity"
})
protected ExitStatus executeCommand(
@NonNull CallingContext callingContext,
diff --git a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/metapath/MetapathCommand.java b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/metapath/MetapathCommand.java
index 903fd1590..0d1a0d79c 100644
--- a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/metapath/MetapathCommand.java
+++ b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/commands/metapath/MetapathCommand.java
@@ -7,6 +7,10 @@
import gov.nist.secauto.metaschema.cli.processor.command.AbstractParentCommand;
+/**
+ * This sub-command implementation contains all command that relate to Metapath
+ * execution.
+ */
public class MetapathCommand
extends AbstractParentCommand {
private static final String COMMAND = "metapath";
diff --git a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/util/LoggingValidationHandler.java b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/util/LoggingValidationHandler.java
index 0fe51e7eb..16ac89d9c 100644
--- a/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/util/LoggingValidationHandler.java
+++ b/metaschema-cli/src/main/java/gov/nist/secauto/metaschema/cli/util/LoggingValidationHandler.java
@@ -26,6 +26,10 @@
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+/**
+ * Supports logging validation findings to the console using ANSI color codes to
+ * improve the visibility of warnings and errors.
+ */
public final class LoggingValidationHandler
extends AbstractValidationResultProcessor {
private static final Logger LOGGER = LogManager.getLogger(LoggingValidationHandler.class);
diff --git a/metaschema-cli/src/test/java/gov/nist/secauto/metaschema/cli/CLITest.java b/metaschema-cli/src/test/java/gov/nist/secauto/metaschema/cli/CLITest.java
index 27efe0397..e9b7e8a79 100644
--- a/metaschema-cli/src/test/java/gov/nist/secauto/metaschema/cli/CLITest.java
+++ b/metaschema-cli/src/test/java/gov/nist/secauto/metaschema/cli/CLITest.java
@@ -39,14 +39,13 @@ void evaluateResult(@NonNull ExitStatus status, @NonNull ExitCode expectedCode,
@NonNull Class extends Throwable> thrownClass) {
status.generateMessage(true);
Throwable thrown = status.getThrowable();
- assert thrown != null;
- assertAll(() -> assertEquals(expectedCode, status.getExitCode(), "exit code mismatch"),
- () -> assertEquals(thrownClass, thrown.getClass(), "expected Throwable mismatch"));
+ assertAll(
+ () -> assertEquals(expectedCode, status.getExitCode(), "exit code mismatch"),
+ () -> assertEquals(thrownClass, thrown == null ? null : thrown.getClass(), "expected Throwable mismatch"));
}
private static Stream providesValues() {
- @SuppressWarnings("serial")
- List values = new LinkedList<>() {
+ @SuppressWarnings("serial") List values = new LinkedList<>() {
{
add(Arguments.of(new String[] {}, ExitCode.INVALID_COMMAND,
NO_EXCEPTION_CLASS));
@@ -159,7 +158,7 @@ private static Stream providesValues() {
"--disable-schema-validation"
},
// fail due to missing element during parsing
- ExitCode.IO_ERROR, java.io.IOException.class));
+ ExitCode.FAIL, NO_EXCEPTION_CLASS));
add(Arguments.of(
new String[] { "validate-content",
"-m",
@@ -181,15 +180,6 @@ private static Stream providesValues() {
"../core/metaschema/schema/metaschema/metaschema-module-metaschema.xml",
},
ExitCode.OK, NO_EXCEPTION_CLASS));
- add(Arguments.of(
- new String[] { "validate-content",
- "-m",
- "src/test/resources/content/215-module.xml",
- "src/test/resources/content/215.xml",
- "--disable-schema-validation",
- "--show-stack-trace"
- },
- ExitCode.FAIL, NO_EXCEPTION_CLASS));
}
};
@@ -214,10 +204,10 @@ void testAllCommands(@NonNull String[] args, @NonNull ExitCode expectedExitCode,
void test() {
String[] cliArgs = { "validate-content",
"-m",
- "src/test/resources/content/215-module.xml",
- "src/test/resources/content/215.xml",
- "--disable-schema-validation",
- "--show-stack-trace"
+ "src/test/resources/content/schema-validation-module.xml",
+ "src/test/resources/content/schema-validation-module-missing-required.xml",
+ "--as=xml",
+ "--disable-schema-validation"
};
CLI.runCli(cliArgs);
}
diff --git a/metaschema-cli/src/test/java/gov/nist/secauto/metaschema/cli/commands/metapath/EvaluateMetapathSubCommandTest.java b/metaschema-cli/src/test/java/gov/nist/secauto/metaschema/cli/commands/metapath/EvaluateMetapathSubCommandTest.java
index b307f3fd1..9949e77fd 100644
--- a/metaschema-cli/src/test/java/gov/nist/secauto/metaschema/cli/commands/metapath/EvaluateMetapathSubCommandTest.java
+++ b/metaschema-cli/src/test/java/gov/nist/secauto/metaschema/cli/commands/metapath/EvaluateMetapathSubCommandTest.java
@@ -11,13 +11,13 @@
import org.junit.jupiter.api.Test;
-import nl.altindag.console.ConsoleCaptor;
+import nl.altindag.log.LogCaptor;
class EvaluateMetapathSubCommandTest {
@Test
void test() {
- try (ConsoleCaptor consoleCaptor = new ConsoleCaptor()) {
+ try (LogCaptor captor = LogCaptor.forRoot()) {
String[] args
= {
"metapath",
@@ -26,7 +26,7 @@ void test() {
"3 + 4 + 5",
"--show-stack-trace" };
CLI.runCli(args);
- assertThat(consoleCaptor.getStandardOutput()).contains("12");
+ assertThat(captor.getInfoLogs().contains("12"));
}
}
}
diff --git a/metaschema-maven-plugin/pom.xml b/metaschema-maven-plugin/pom.xml
index 6646e9a95..2ebf37fdd 100644
--- a/metaschema-maven-plugin/pom.xml
+++ b/metaschema-maven-plugin/pom.xml
@@ -95,6 +95,14 @@
+
+
+ src/main/resources
+
+
+ ${project.build.directory}/generated-resources/maven-plugin
+
+
@@ -129,6 +137,11 @@
org.apache.maven.pluginsmaven-plugin-plugin
+
+ metaschema
+ true
+ ${project.build.directory}/classes/META-INF/maven
+ default-addPluginArtifactMetadata
@@ -138,21 +151,37 @@
- default-descriptor
- process-classes
+ help-mojo
- descriptor
+ helpmojo
- metaschema
- false
+ ${project.build.directory}/generated-sources/maven-plugin
- help-mojo
+ default-descriptor
- helpmojo
+ descriptor
+
+
+
+
+
+ org.codehaus.mojo
+ build-helper-maven-plugin
+
+
+ add-generated-sources
+ generate-sources
+
+ add-source
+
+
+
+
+
diff --git a/metaschema-maven-plugin/src/main/java/gov/nist/secauto/metaschema/maven/plugin/AbstractMetaschemaMojo.java b/metaschema-maven-plugin/src/main/java/gov/nist/secauto/metaschema/maven/plugin/AbstractMetaschemaMojo.java
index ce70fb581..b3dea218e 100644
--- a/metaschema-maven-plugin/src/main/java/gov/nist/secauto/metaschema/maven/plugin/AbstractMetaschemaMojo.java
+++ b/metaschema-maven-plugin/src/main/java/gov/nist/secauto/metaschema/maven/plugin/AbstractMetaschemaMojo.java
@@ -617,7 +617,7 @@ public IProduction generateClasses(@NonNull IModule module) {
return production;
}
- public void compileClasses(@NonNull IProduction production, @NonNull Path classDir)
+ private void compileClasses(@NonNull IProduction production, @NonNull Path classDir)
throws IOException, DependencyResolutionRequiredException {
List classesToCompile = production.getGeneratedClasses().collect(Collectors.toList());
diff --git a/pom.xml b/pom.xml
index bb7994603..6790b7552 100644
--- a/pom.xml
+++ b/pom.xml
@@ -41,7 +41,6 @@
3.8.14.13.2
- 1.1.13.26.31.9.04.4
@@ -177,12 +176,6 @@
cli-processor${project.version}