diff --git a/cli-processor/src/main/java-templates/gov/nist/secauto/metaschema/cli/processor/ProcessorVersion.java b/cli-processor/src/main/java-templates/gov/nist/secauto/metaschema/cli/processor/ProcessorVersion.java
new file mode 100644
index 000000000..b9450bf16
--- /dev/null
+++ b/cli-processor/src/main/java-templates/gov/nist/secauto/metaschema/cli/processor/ProcessorVersion.java
@@ -0,0 +1,57 @@
+
+
+package gov.nist.secauto.metaschema.cli.processor;
+
+import gov.nist.secauto.metaschema.core.util.IVersionInfo;
+
+/**
+ * Provides version information for this library.
+ *
+ * This class exposes build-time metadata including version numbers, build
+ * timestamps, and Git repository information.
+ */
+public class ProcessorVersion implements IVersionInfo {
+
+ private static final String NAME = "${project.name}";
+ private static final String VERSION = "${project.version}";
+ private static final String BUILD_TIMESTAMP = "${timestamp}";
+ private static final String COMMIT = "@git.commit.id.abbrev@";
+ private static final String BRANCH = "@git.branch@";
+ private static final String CLOSEST_TAG = "@git.closest.tag.name@";
+ private static final String ORIGIN = "@git.remote.origin.url@";
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+
+ @Override
+ public String getVersion() {
+ return VERSION;
+ }
+
+ @Override
+ public String getBuildTimestamp() {
+ return BUILD_TIMESTAMP;
+ }
+
+ @Override
+ public String getGitOriginUrl() {
+ return ORIGIN;
+ }
+
+ @Override
+ public String getGitCommit() {
+ return COMMIT;
+ }
+
+ @Override
+ public String getGitBranch() {
+ return BRANCH;
+ }
+
+ @Override
+ public String getGitClosestTag() {
+ return CLOSEST_TAG;
+ }
+}
diff --git a/cli-processor/src/main/java-templates/gov/nist/secauto/metaschema/cli/processor/Version.java b/cli-processor/src/main/java-templates/gov/nist/secauto/metaschema/cli/processor/Version.java
deleted file mode 100644
index 5b87b3732..000000000
--- a/cli-processor/src/main/java-templates/gov/nist/secauto/metaschema/cli/processor/Version.java
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-package gov.nist.secauto.metaschema.cli.processor;
-
-import static org.fusesource.jansi.Ansi.ansi;
-
-import java.io.PrintStream;
-
-public class Version implements VersionInfo {
-
- public static final String VERSION = "${project.version}";
- public static final String BUILD_TIMESTAMP = "${timestamp}";
- public static final String COMMIT = "@git.commit.id.abbrev@";
-
- public Version() {
- }
-
- @Override
- public String getVersion() {
- return VERSION;
- }
-
- @Override
- public String getBuildTime() {
- return BUILD_TIMESTAMP;
- }
-
- @Override
- public String getCommit() {
- return COMMIT;
- }
-
- @Override
- public void generateExtraInfo(PrintStream out) {
- out.println(ansi()
- .a("Metaschema version ").bold().a(getVersion()).boldOff()
- .a(" on commit ").bold().a(getCommit()).boldOff()
- .a(" built at ").bold().a( getBuildTime()).reset());
- }
-}
diff --git a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/AbstractExitStatus.java b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/AbstractExitStatus.java
index 72ec3c8e0..d8e1667fa 100644
--- a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/AbstractExitStatus.java
+++ b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/AbstractExitStatus.java
@@ -13,6 +13,14 @@
import edu.umd.cs.findbugs.annotations.Nullable;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+/**
+ * Records information about the exit status of a CLI command.
+ *
+ * This abstract class provides base functionality for handling CLI command exit
+ * statuses, including error logging and throwable management. Implementing
+ * classes must provide the {@link #getMessage()} implementation to define the
+ * status message content.
+ */
public abstract class AbstractExitStatus implements ExitStatus {
private static final Logger LOGGER = LogManager.getLogger(AbstractExitStatus.class);
@@ -61,8 +69,16 @@ public ExitStatus withThrowable(@NonNull Throwable throwable) {
@Nullable
protected abstract String getMessage();
- @Override
- public void generateMessage(boolean showStackTrace) {
+ /**
+ * Determines the appropriate LogBuilder based on the exit code status. For
+ * non-positive exit codes (success/info), returns an INFO level builder. For
+ * positive exit codes (errors), returns an ERROR level builder.
+ *
+ * @return the appropriate LogBuilder based on exit status, or {@code null} if
+ * logging is disabled at the determined level
+ */
+ @Nullable
+ private LogBuilder getLogBuilder() {
LogBuilder logBuilder = null;
if (getExitCode().getStatusCode() <= 0) {
if (LOGGER.isInfoEnabled()) {
@@ -71,25 +87,41 @@ public void generateMessage(boolean showStackTrace) {
} else if (LOGGER.isErrorEnabled()) {
logBuilder = LOGGER.atError();
}
+ return logBuilder;
+ }
- if (logBuilder != null) {
- if (showStackTrace && throwable != null) {
- Throwable throwable = getThrowable();
- logBuilder.withThrowable(throwable);
- }
+ /**
+ * Generates and logs a message based on the current exit status. The message is
+ * logged at either INFO level (for success/info status) or ERROR level (for
+ * error status).
+ *
+ * @param showStackTrace
+ * if {@code true} and a throwable is present, includes the stack trace
+ * in the log
+ */
+ @Override
+ public void generateMessage(boolean showStackTrace) {
+ LogBuilder logBuilder = getLogBuilder();
+ if (logBuilder == null) {
+ return;
+ }
- String message = getMessage();
- if (message == null && throwable != null) {
- message = throwable.getLocalizedMessage();
- }
+ boolean useStackTrace = showStackTrace && throwable != null;
+ if (useStackTrace) {
+ logBuilder.withThrowable(throwable);
+ }
- if (message != null && !message.isEmpty()) {
- logBuilder.log(message);
- } else if (showStackTrace && throwable != null) {
- // log the throwable
- logBuilder.log();
- }
+ String message = getMessage();
+ if (throwable != null && message == null) {
+ message = throwable.getLocalizedMessage();
}
+
+ if (message != null && !message.isEmpty()) {
+ logBuilder.log(message);
+ } else if (useStackTrace) {
+ // log the throwable
+ logBuilder.log();
+ } // else avoid an empty log line
}
}
diff --git a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/CLIProcessor.java b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/CLIProcessor.java
index f03af2c72..31a13a2a5 100644
--- a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/CLIProcessor.java
+++ b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/CLIProcessor.java
@@ -49,48 +49,69 @@
import edu.umd.cs.findbugs.annotations.Nullable;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+/**
+ * Processes command line arguments and dispatches called commands.
+ *
+ * This implementation make significant use of the command pattern to support a
+ * delegation chain of commands based on implementations of {@link ICommand}.
+ */
+@SuppressWarnings("PMD.CouplingBetweenObjects")
public class CLIProcessor {
private static final Logger LOGGER = LogManager.getLogger(CLIProcessor.class);
- @SuppressWarnings("null")
+ /**
+ * This option indicates if the help should be shown.
+ */
@NonNull
- public static final Option HELP_OPTION = Option.builder("h")
+ public static final Option HELP_OPTION = ObjectUtils.notNull(Option.builder("h")
.longOpt("help")
.desc("display this help message")
- .build();
- @SuppressWarnings("null")
+ .build());
+ /**
+ * This option indicates if colorized output should be disabled.
+ */
@NonNull
- public static final Option NO_COLOR_OPTION = Option.builder()
+ public static final Option NO_COLOR_OPTION = ObjectUtils.notNull(Option.builder()
.longOpt("no-color")
.desc("do not colorize output")
- .build();
- @SuppressWarnings("null")
+ .build());
+ /**
+ * This option indicates if non-errors should be suppressed.
+ */
@NonNull
- public static final Option QUIET_OPTION = Option.builder("q")
+ public static final Option QUIET_OPTION = ObjectUtils.notNull(Option.builder("q")
.longOpt("quiet")
.desc("minimize output to include only errors")
- .build();
- @SuppressWarnings("null")
+ .build());
+ /**
+ * This option indicates if a strack trace should be shown for an error
+ * {@link ExitStatus}.
+ */
@NonNull
- public static final Option SHOW_STACK_TRACE_OPTION = Option.builder()
+ public static final Option SHOW_STACK_TRACE_OPTION = ObjectUtils.notNull(Option.builder()
.longOpt("show-stack-trace")
.desc("display the stack trace associated with an error")
- .build();
- @SuppressWarnings("null")
+ .build());
+ /**
+ * This option indicates if the version information should be shown.
+ */
@NonNull
- public static final Option VERSION_OPTION = Option.builder()
+ public static final Option VERSION_OPTION = ObjectUtils.notNull(Option.builder()
.longOpt("version")
.desc("display the application version")
- .build();
- @SuppressWarnings("null")
+ .build());
+
@NonNull
- public static final List OPTIONS = List.of(
+ private static final List OPTIONS = ObjectUtils.notNull(List.of(
HELP_OPTION,
NO_COLOR_OPTION,
QUIET_OPTION,
SHOW_STACK_TRACE_OPTION,
- VERSION_OPTION);
+ VERSION_OPTION));
+ /**
+ * Used to identify the version info for the command.
+ */
public static final String COMMAND_VERSION = "http://csrc.nist.gov/ns/metaschema-java/cli/command-version";
@NonNull
@@ -100,6 +121,12 @@ public class CLIProcessor {
@NonNull
private final Map versionInfos;
+ /**
+ * The main entry point for command execution.
+ *
+ * @param args
+ * the command line arguments to process
+ */
public static void main(String... args) {
System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager");
CLIProcessor processor = new CLIProcessor("metaschema-cli");
@@ -111,11 +138,28 @@ public static void main(String... args) {
System.exit(processor.process(args).getExitCode().getStatusCode());
}
- @SuppressWarnings("null")
- public CLIProcessor(@NonNull String exec) {
- this(exec, Map.of());
+ /**
+ * The main entry point for CLI processing.
+ *
+ * This uses the build-in version information.
+ *
+ * @param args
+ * the command line arguments
+ */
+ public CLIProcessor(@NonNull String args) {
+ this(args, CollectionUtil.singletonMap(COMMAND_VERSION, new ProcessorVersion()));
}
+ /**
+ * The main entry point for CLI processing.
+ *
+ * This uses the provided version information.
+ *
+ * @param exec
+ * the command name
+ * @param versionInfos
+ * the version info to display when the version option is provided
+ */
public CLIProcessor(@NonNull String exec, @NonNull Map versionInfos) {
this.exec = exec;
this.versionInfos = versionInfos;
@@ -142,6 +186,12 @@ public Map getVersionInfos() {
return versionInfos;
}
+ /**
+ * Register a new command handler.
+ *
+ * @param handler
+ * the command handler to register
+ */
public void addCommandHandler(@NonNull ICommand handler) {
commands.add(handler);
}
@@ -186,11 +236,21 @@ private ExitStatus parseCommand(String... args) {
return status;
}
+ /**
+ * Get the root-level commands.
+ *
+ * @return the list of commands
+ */
@NonNull
protected final List getTopLevelCommands() {
return CollectionUtil.unmodifiableList(commands);
}
+ /**
+ * Get the root-level commands, mapped from name to command.
+ *
+ * @return the map of command names to command
+ */
@NonNull
protected final Map getTopLevelCommandsByName() {
return ObjectUtils.notNull(getTopLevelCommands()
@@ -203,6 +263,9 @@ private static void handleNoColor() {
AnsiConsole.systemUninstall();
}
+ /**
+ * Configure the logger to only report errors.
+ */
public static void handleQuiet() {
LoggerContext ctx = (LoggerContext) LogManager.getContext(false); // NOPMD not closable here
Configuration config = ctx.getConfiguration();
@@ -214,6 +277,9 @@ public static void handleQuiet() {
}
}
+ /**
+ * Output version information.
+ */
protected void showVersion() {
@SuppressWarnings("resource")
PrintStream out = AnsiConsole.out(); // NOPMD - not owner
@@ -235,14 +301,12 @@ protected void showVersion() {
out.flush();
}
- // @SuppressWarnings("null")
- // @NonNull
- // public String[] getArgArray() {
- // return Stream.concat(options.stream(), extraArgs.stream()).toArray(size ->
- // new String[size]);
- // }
-
- public class CallingContext {
+ /**
+ * Records information about the command line options and called command
+ * hierarchy.
+ */
+ @SuppressWarnings("PMD.GodClass")
+ public final class CallingContext {
@NonNull
private final List options;
@NonNull
@@ -253,7 +317,7 @@ public class CallingContext {
private final List extraArgs;
@SuppressFBWarnings(value = "CT_CONSTRUCTOR_THROW", justification = "Use of final fields")
- public CallingContext(@NonNull List args) {
+ private CallingContext(@NonNull List args) {
@SuppressWarnings("PMD.LooseCoupling")
LinkedList calledCommands = new LinkedList<>();
List options = new LinkedList<>(OPTIONS);
@@ -286,18 +350,33 @@ public CallingContext(@NonNull List args) {
this.extraArgs = CollectionUtil.unmodifiableList(extraArgs);
}
+ /**
+ * Get the command line processor instance that generated this calling context.
+ *
+ * @return the instance
+ */
@NonNull
public CLIProcessor getCLIProcessor() {
return CLIProcessor.this;
}
+ /**
+ * Get the command that was triggered by the CLI arguments.
+ *
+ * @return the command or {@code null} if no command was triggered
+ */
@Nullable
public ICommand getTargetCommand() {
return targetCommand;
}
+ /**
+ * Get the options that are in scope for the current command context.
+ *
+ * @return the list of options
+ */
@NonNull
- protected List getOptionsList() {
+ private List getOptionsList() {
return options;
}
@@ -306,12 +385,22 @@ private List getCalledCommands() {
return calledCommands;
}
+ /**
+ * Get any left over arguments that were not consumed by CLI options.
+ *
+ * @return the list of remaining arguments, which may be empty
+ */
@NonNull
- protected List getExtraArgs() {
+ private List getExtraArgs() {
return extraArgs;
}
- protected Options toOptions() {
+ /**
+ * Get the collections of in scope options as an options group.
+ *
+ * @return the options group
+ */
+ private Options toOptions() {
Options retval = new Options();
for (Option option : getOptionsList()) {
retval.addOption(option);
@@ -319,9 +408,23 @@ protected Options toOptions() {
return retval;
}
- @SuppressWarnings("PMD.OnlyOneReturn") // readability
+ /**
+ * Process the command identified by the CLI arguments.
+ *
+ * @return the result of processing the command
+ */
+ @SuppressWarnings({
+ "PMD.OnlyOneReturn",
+ "PMD.NPathComplexity",
+ "PMD.CyclomaticComplexity"
+ })
@NonNull
public ExitStatus processCommand() {
+ // TODO: Consider refactoring as follows to reduce complexity:
+ // - Extract the parsing logic for each phase into separate methods (e.g.,
+ // parsePhaseOneOptions, parsePhaseTwoOptions).
+ // - Encapsulate error handling into dedicated methods.
+ // - Separate command execution logic into its own method if possible.
CommandLineParser parser = new DefaultParser();
// this uses a three phase approach where:
@@ -363,35 +466,11 @@ public ExitStatus processCommand() {
ICommand targetCommand = getTargetCommand();
if (targetCommand != null) {
- if (targetCommand.isSubCommandRequired()) {
- return handleError(
- ExitCode.INVALID_ARGUMENTS
- .exitMessage("Please choose a valid sub-command."),
- cmdLine,
- true);
- }
-
- List extraArguments = targetCommand.getExtraArguments();
- int maxArguments = extraArguments.size();
-
- List actualArgs = cmdLine.getArgList();
- int actualArgsSize = actualArgs.size();
- if (actualArgs.size() > maxArguments) {
- return handleError(
- ExitCode.INVALID_ARGUMENTS
- .exitMessage("The provided extra arguments exceed the number of allowed arguments."),
- cmdLine,
- true);
- }
-
- List requiredExtraArguments = targetCommand.getExtraArguments().stream()
- .filter(ExtraArgument::isRequired)
- .collect(Collectors.toUnmodifiableList());
-
- if (actualArgsSize < requiredExtraArguments.size()) {
+ try {
+ targetCommand.validateExtraArguments(this, cmdLine);
+ } catch (InvalidArgumentException ex) {
return handleError(
- ExitCode.INVALID_ARGUMENTS
- .exitMessage("Please provide the required extra arguments."),
+ ExitCode.INVALID_ARGUMENTS.exitMessage(ex.getLocalizedMessage()),
cmdLine,
true);
}
@@ -418,12 +497,19 @@ public ExitStatus processCommand() {
return invokeCommand(cmdLine);
}
+ /**
+ * Directly execute the logic associated with the command.
+ *
+ * @param cmdLine
+ * the command line information
+ * @return the result of executing the command
+ */
@SuppressWarnings({
"PMD.OnlyOneReturn", // readability
"PMD.AvoidCatchingGenericException" // needed here
})
@NonNull
- protected ExitStatus invokeCommand(@NonNull CommandLine cmdLine) {
+ private ExitStatus invokeCommand(@NonNull CommandLine cmdLine) {
ExitStatus retval;
try {
ICommand targetCommand = getTargetCommand();
@@ -458,6 +544,17 @@ protected ExitStatus invokeCommand(@NonNull CommandLine cmdLine) {
return retval;
}
+ /**
+ * Handle an error that occurred while executing the command.
+ *
+ * @param exitStatus
+ * the execution result
+ * @param cmdLine
+ * the command line information
+ * @param showHelp
+ * if {@code true} show the help information
+ * @return the resulting exit status
+ */
@NonNull
public ExitStatus handleError(
@NonNull ExitStatus exitStatus,
@@ -470,6 +567,14 @@ public ExitStatus handleError(
return exitStatus;
}
+ /**
+ * Generate the help message and exit status for an invalid command using the
+ * provided message.
+ *
+ * @param message
+ * the error message
+ * @return the resulting exit status
+ */
@NonNull
public ExitStatus handleInvalidCommand(
@NonNull String message) {
@@ -486,7 +591,7 @@ public ExitStatus handleInvalidCommand(
* @return the header or {@code null}
*/
@Nullable
- protected String buildHelpHeader() {
+ private String buildHelpHeader() {
// TODO: build a suitable header
return null;
}
@@ -548,7 +653,7 @@ private String buildHelpFooter() {
*
* @return the CLI syntax to display in help output
*/
- protected String buildHelpCliSyntax() {
+ private String buildHelpCliSyntax() {
StringBuilder builder = new StringBuilder(64);
builder.append(getExec());
@@ -565,20 +670,7 @@ protected String buildHelpCliSyntax() {
if (targetCommand == null) {
builder.append(" ");
} else {
- Collection subCommands = targetCommand.getSubCommands();
-
- if (!subCommands.isEmpty()) {
- builder.append(' ');
- if (!targetCommand.isSubCommandRequired()) {
- builder.append('[');
- }
-
- builder.append("");
-
- if (!targetCommand.isSubCommandRequired()) {
- builder.append(']');
- }
- }
+ builder.append(getSubCommands(targetCommand));
}
// output required options
@@ -601,29 +693,56 @@ protected String buildHelpCliSyntax() {
// output extra arguments
if (targetCommand != null) {
// handle extra arguments
- for (ExtraArgument argument : targetCommand.getExtraArguments()) {
- builder.append(' ');
- if (!argument.isRequired()) {
- builder.append('[');
- }
+ builder.append(getExtraArguments(targetCommand));
+ }
- builder.append('<')
- .append(argument.getName())
- .append('>');
+ String retval = builder.toString();
+ assert retval != null;
+ return retval;
+ }
- if (argument.getNumber() > 1) {
- builder.append("...");
- }
+ @NonNull
+ private CharSequence getSubCommands(ICommand targetCommand) {
+ Collection subCommands = targetCommand.getSubCommands();
+
+ StringBuilder builder = new StringBuilder();
+ if (!subCommands.isEmpty()) {
+ builder.append(' ');
+ if (!targetCommand.isSubCommandRequired()) {
+ builder.append('[');
+ }
- if (!argument.isRequired()) {
- builder.append(']');
- }
+ builder.append("");
+
+ if (!targetCommand.isSubCommandRequired()) {
+ builder.append(']');
}
}
+ return builder;
+ }
- String retval = builder.toString();
- assert retval != null;
- return retval;
+ @NonNull
+ private CharSequence getExtraArguments(@NonNull ICommand targetCommand) {
+ StringBuilder builder = new StringBuilder();
+ for (ExtraArgument argument : targetCommand.getExtraArguments()) {
+ builder.append(' ');
+ if (!argument.isRequired()) {
+ builder.append('[');
+ }
+
+ builder.append('<')
+ .append(argument.getName())
+ .append('>');
+
+ if (argument.getNumber() > 1) {
+ builder.append("...");
+ }
+
+ if (!argument.isRequired()) {
+ builder.append(']');
+ }
+ }
+ return builder;
}
/**
diff --git a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/ExitCode.java b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/ExitCode.java
index b62d898b7..238b78395 100644
--- a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/ExitCode.java
+++ b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/ExitCode.java
@@ -7,6 +7,9 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * An enumeration of supported exit code values.
+ */
public enum ExitCode {
/**
* The command executed without issue.
diff --git a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/ExitStatus.java b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/ExitStatus.java
index 22ae94680..be5709cfd 100644
--- a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/ExitStatus.java
+++ b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/ExitStatus.java
@@ -8,6 +8,10 @@
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
+/**
+ * Implementations provide details around the result of processing a set of
+ * command line arguments.
+ */
public interface ExitStatus {
/**
* Get the exit code information associated with this exit status.
@@ -17,6 +21,11 @@ public interface ExitStatus {
@NonNull
ExitCode getExitCode();
+ /**
+ * Get a throwable that is associated with this exit status.
+ *
+ * @return the throwable or {@code null} if no throwable is associated
+ */
@Nullable
Throwable getThrowable();
diff --git a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/InvalidArgumentException.java b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/InvalidArgumentException.java
index a54ff02d1..bc514b0c2 100644
--- a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/InvalidArgumentException.java
+++ b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/InvalidArgumentException.java
@@ -11,6 +11,10 @@
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+/**
+ * Thrown when an option argument is found to be invalid during parsing of a
+ * command-line.
+ */
public class InvalidArgumentException
extends ParseException {
diff --git a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/MessageExitStatus.java b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/MessageExitStatus.java
index e04c71c6a..ce2e4bf76 100644
--- a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/MessageExitStatus.java
+++ b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/MessageExitStatus.java
@@ -5,12 +5,20 @@
package gov.nist.secauto.metaschema.cli.processor;
+import gov.nist.secauto.metaschema.core.util.CollectionUtil;
+import gov.nist.secauto.metaschema.core.util.ObjectUtils;
+
import java.util.Arrays;
-import java.util.Collections;
import java.util.List;
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * An {@link ExitStatus} implementation with an associated message.
+ *
+ * The message arguments are stored in an unmodifiable list to ensure
+ * thread-safety and immutability.
+ */
public class MessageExitStatus
extends AbstractExitStatus {
private final List messageArguments;
@@ -26,11 +34,8 @@ public class MessageExitStatus
*/
public MessageExitStatus(@NonNull ExitCode code, @NonNull Object... messageArguments) {
super(code);
- if (messageArguments.length == 0) {
- this.messageArguments = Collections.emptyList();
- } else {
- this.messageArguments = Arrays.asList(messageArguments);
- }
+ this.messageArguments = CollectionUtil.unmodifiableList(
+ ObjectUtils.notNull(Arrays.asList(messageArguments)));
}
@Override
diff --git a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/NonMessageExitStatus.java b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/NonMessageExitStatus.java
index 8c0673e96..8cdfa64a9 100644
--- a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/NonMessageExitStatus.java
+++ b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/NonMessageExitStatus.java
@@ -7,19 +7,33 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * An {@link ExitStatus} implementation that represents a status without an
+ * associated message.
+ *
+ * This implementation is useful when only the exit code needs to be
+ * communicated, without additional context or explanation.
+ */
public class NonMessageExitStatus
extends AbstractExitStatus {
/**
- * Construct a new message status.
+ * Construct a new exit status without an associated message.
+ *
+ * @param code
+ * the non-null exit code representing the status
*/
NonMessageExitStatus(@NonNull ExitCode code) {
super(code);
}
+ /**
+ * {@inheritDoc}
+ *
+ * @return {@code null} as this implementation does not support messages
+ */
@Override
protected String getMessage() {
- // always null
return null;
}
}
diff --git a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/OptionUtils.java b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/OptionUtils.java
index c918fee3b..b64822830 100644
--- a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/OptionUtils.java
+++ b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/OptionUtils.java
@@ -9,12 +9,22 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * A collection of utilities for handling command line options.
+ */
public final class OptionUtils {
private OptionUtils() {
// disable construction
}
+ /**
+ * Generate the argument text for the given option.
+ *
+ * @param option
+ * the CLI option
+ * @return the argument text
+ */
@NonNull
public static String toArgument(@NonNull Option option) {
return option.hasLongOpt() ? "--" + option.getLongOpt() : "-" + option.getOpt();
diff --git a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/VersionInfo.java b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/VersionInfo.java
deleted file mode 100644
index 5bd8b6863..000000000
--- a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/VersionInfo.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * SPDX-FileCopyrightText: none
- * SPDX-License-Identifier: CC0-1.0
- */
-
-package gov.nist.secauto.metaschema.cli.processor;
-
-import java.io.PrintStream;
-
-import edu.umd.cs.findbugs.annotations.NonNull;
-
-public interface VersionInfo {
- @NonNull
- String getVersion();
-
- @NonNull
- String getBuildTime();
-
- @NonNull
- String getCommit();
-
- void generateExtraInfo(@NonNull PrintStream out);
-}
diff --git a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/AbstractCommandExecutor.java b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/AbstractCommandExecutor.java
index 16176edc9..046a1efa5 100644
--- a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/AbstractCommandExecutor.java
+++ b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/AbstractCommandExecutor.java
@@ -12,24 +12,48 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * A base class for implementation that perform the operation supported by a
+ * command.
+ */
public abstract class AbstractCommandExecutor implements ICommandExecutor {
@NonNull
private final CallingContext callingContext;
@NonNull
private final CommandLine commandLine;
- public AbstractCommandExecutor(
+ /**
+ * Construct a new command executor.
+ *
+ * @param callingContext
+ * the context of the command execution
+ * @param commandLine
+ * the parsed command line details
+ */
+ protected AbstractCommandExecutor(
@NonNull CallingContext callingContext,
@NonNull CommandLine commandLine) {
this.callingContext = callingContext;
this.commandLine = commandLine;
}
+ /**
+ * Get the context of the command execution, which provides access to the
+ * execution environment needed for command processing.
+ *
+ * @return the context
+ */
@NonNull
protected CallingContext getCallingContext() {
return callingContext;
}
+ /**
+ * Get the parsed command line details containing the command options and
+ * arguments provided by the user during execution.
+ *
+ * @return the cli details
+ */
@NonNull
protected CommandLine getCommandLine() {
return commandLine;
@@ -38,6 +62,11 @@ protected CommandLine getCommandLine() {
@Override
public abstract void execute() throws CommandExecutionException;
+ /**
+ * Get the command associated with this execution.
+ *
+ * @return the command
+ */
@NonNull
protected ICommand getCommand() {
return ObjectUtils.requireNonNull(getCallingContext().getTargetCommand());
diff --git a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/AbstractParentCommand.java b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/AbstractParentCommand.java
index 9655aa988..047f14e66 100644
--- a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/AbstractParentCommand.java
+++ b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/AbstractParentCommand.java
@@ -8,6 +8,7 @@
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.core.util.ObjectUtils;
import org.apache.commons.cli.CommandLine;
@@ -19,17 +20,30 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * A base class for a command that supports hierarchical command structure with
+ * child commands. This class provides the foundation for implementing complex
+ * CLI commands that can have multiple levels of sub-commands.
+ *
+ * This class is thread-safe and supports concurrent access to command handlers.
+ */
public abstract class AbstractParentCommand implements ICommand {
@NonNull
private final Map commandToSubcommandHandlerMap;
- private final boolean subCommandRequired;
- @SuppressWarnings("null")
- protected AbstractParentCommand(boolean subCommandRequired) {
- this.commandToSubcommandHandlerMap = Collections.synchronizedMap(new LinkedHashMap<>());
- this.subCommandRequired = subCommandRequired;
+ /**
+ * Construct a new parent command.
+ */
+ protected AbstractParentCommand() {
+ this.commandToSubcommandHandlerMap = ObjectUtils.notNull(Collections.synchronizedMap(new LinkedHashMap<>()));
}
+ /**
+ * Add a child command.
+ *
+ * @param handler
+ * the command handler for the child command
+ */
protected final void addCommandHandler(ICommand handler) {
String commandName = handler.getName();
this.commandToSubcommandHandlerMap.put(commandName, handler);
@@ -40,15 +54,14 @@ public ICommand getSubCommandByName(String name) {
return commandToSubcommandHandlerMap.get(name);
}
- @SuppressWarnings("null")
@Override
public Collection getSubCommands() {
- return Collections.unmodifiableCollection(commandToSubcommandHandlerMap.values());
+ return ObjectUtils.notNull(Collections.unmodifiableCollection(commandToSubcommandHandlerMap.values()));
}
@Override
public boolean isSubCommandRequired() {
- return subCommandRequired;
+ return true;
}
@Override
@@ -57,9 +70,9 @@ public ICommandExecutor newExecutor(CallingContext callingContext, CommandLine c
}
@NonNull
- protected ExitStatus executeCommand(
+ private ExitStatus executeCommand(
@NonNull CallingContext callingContext,
- @NonNull CommandLine commandLine) {
+ @SuppressWarnings("unused") @NonNull CommandLine commandLine) {
callingContext.showHelp();
ExitStatus status;
if (isSubCommandRequired()) {
diff --git a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/AbstractTerminalCommand.java b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/AbstractTerminalCommand.java
index 65da54530..2d7668319 100644
--- a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/AbstractTerminalCommand.java
+++ b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/AbstractTerminalCommand.java
@@ -12,41 +12,81 @@
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.Collection;
-import java.util.Collections;
import edu.umd.cs.findbugs.annotations.NonNull;
import nl.talsmasoftware.lazy4j.Lazy;
+/**
+ * A base class for terminal commands in the command processing hierarchy.
+ * Terminal commands represent leaf nodes that perform actual operations and
+ * cannot have child commands.
+ */
public abstract class AbstractTerminalCommand implements ICommand {
- private static Lazy currentWorkingDirectory = Lazy.lazy(() -> Paths.get("").toAbsolutePath());
-
- @SuppressWarnings("null")
- @Override
- public Collection getSubCommands() {
- return Collections.emptyList();
- }
-
- @Override
- public boolean isSubCommandRequired() {
- return false;
- }
+ private static Lazy currentWorkingDirectory = Lazy.lazy(() -> Paths.get(System.getProperty("user.dir")));
+ /**
+ * A utility method that can be used to get the current working directory.
+ *
+ * This method is thread-safe due to lazy initialization.
+ *
+ * @return the current working directory
+ */
@NonNull
protected static Path getCurrentWorkingDirectory() {
return ObjectUtils.notNull(currentWorkingDirectory.get());
}
+ /**
+ * A utility method that can be used to resolve a path against the current
+ * working directory.
+ *
+ * If the path is already absolute, then the provided path is returned.
+ *
+ * @param path
+ * the path to resolve
+ *
+ * @return the resolved path
+ */
@NonNull
protected static Path resolveAgainstCWD(@NonNull Path path) {
- return ObjectUtils.notNull(getCurrentWorkingDirectory().resolve(path).normalize());
+
+ return path.isAbsolute()
+ ? path
+ : ObjectUtils.notNull(getCurrentWorkingDirectory().resolve(path).normalize());
}
+ /**
+ * A utility method that can be used to resolve a URI against the URI for the
+ * current working directory.
+ *
+ * If the URI is already absolute, then the provided URI is returned.
+ *
+ * The path is normalized after resolution to remove any redundant name elements
+ * (like "." or "..").
+ *
+ *
+ * @param uri
+ * the uri to resolve
+ *
+ * @return the resolved URI
+ */
@NonNull
protected static URI resolveAgainstCWD(@NonNull URI uri) {
- return ObjectUtils.notNull(getCurrentWorkingDirectory().toUri().resolve(uri.normalize()));
+ return uri.isAbsolute()
+ ? uri
+ : ObjectUtils.notNull(getCurrentWorkingDirectory().toUri().resolve(uri.normalize()));
}
+ /**
+ * A utility method that can be used to resolve a URI (as a string) against the
+ * URI for the current working directory.
+ *
+ * @param uri
+ * the uri to resolve
+ * @return the resolved URI
+ * @throws URISyntaxException
+ * if the provided URI is not a valid URI
+ */
@NonNull
protected static URI resolveAgainstCWD(@NonNull String uri) throws URISyntaxException {
return UriUtils.toUri(uri, ObjectUtils.notNull(getCurrentWorkingDirectory().toUri()));
diff --git a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/CommandService.java b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/CommandService.java
index dfbc135c1..abd873232 100644
--- a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/CommandService.java
+++ b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/CommandService.java
@@ -5,6 +5,8 @@
package gov.nist.secauto.metaschema.cli.processor.command;
+import gov.nist.secauto.metaschema.core.util.ObjectUtils;
+
import java.util.List;
import java.util.ServiceLoader;
import java.util.ServiceLoader.Provider;
@@ -13,8 +15,16 @@
import edu.umd.cs.findbugs.annotations.NonNull;
import nl.talsmasoftware.lazy4j.Lazy;
+/**
+ * A service that loads commands using SPI.
+ *
+ * This class implements the singleton pattern to ensure a single instance of
+ * the command service is used throughout the application.
+ *
+ * @see ServiceLoader for more information
+ */
public final class CommandService {
- private static final Lazy INSTANCE = Lazy.lazy(() -> new CommandService());
+ private static final Lazy INSTANCE = Lazy.lazy(CommandService::new);
@NonNull
private final ServiceLoader loader;
@@ -27,7 +37,14 @@ public static CommandService getInstance() {
return INSTANCE.get();
}
- public CommandService() {
+ /**
+ * Construct a new service.
+ *
+ * Initializes the ServiceLoader for ICommand implementations.
+ *
+ * This constructor is private to enforce the singleton pattern.
+ */
+ private CommandService() {
ServiceLoader loader = ServiceLoader.load(ICommand.class);
assert loader != null;
this.loader = loader;
@@ -43,11 +60,15 @@ private ServiceLoader getLoader() {
return loader;
}
- @SuppressWarnings("null")
+ /**
+ * Get the loaded commands.
+ *
+ * @return the list of loaded commands
+ */
@NonNull
public List getCommands() {
- return getLoader().stream()
+ return ObjectUtils.notNull(getLoader().stream()
.map(Provider::get)
- .collect(Collectors.toUnmodifiableList());
+ .collect(Collectors.toUnmodifiableList()));
}
}
diff --git a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/DefaultExtraArgument.java b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/DefaultExtraArgument.java
deleted file mode 100644
index 5149cc7a0..000000000
--- a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/DefaultExtraArgument.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SPDX-FileCopyrightText: none
- * SPDX-License-Identifier: CC0-1.0
- */
-
-package gov.nist.secauto.metaschema.cli.processor.command;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-
-public class DefaultExtraArgument implements ExtraArgument {
- private final String name;
- private final boolean required;
- private final int number;
-
- @SuppressFBWarnings(value = "CT_CONSTRUCTOR_THROW", justification = "Use of final fields")
- public DefaultExtraArgument(String name, boolean required) {
- this(name, required, 1);
- }
-
- @SuppressFBWarnings(value = "CT_CONSTRUCTOR_THROW", justification = "Use of final fields")
- public DefaultExtraArgument(String name, boolean required, int number) {
- if (number < 1) {
- throw new IllegalArgumentException("number must be a positive value");
- }
- this.name = name;
- this.required = required;
- this.number = number;
- }
-
- @Override
- public String getName() {
- return name;
- }
-
- @Override
- public boolean isRequired() {
- return required;
- }
-
- @Override
- public int getNumber() {
- return number;
- }
-
-}
diff --git a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/ExtraArgument.java b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/ExtraArgument.java
index c7ff59180..4d0933532 100644
--- a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/ExtraArgument.java
+++ b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/ExtraArgument.java
@@ -5,15 +5,52 @@
package gov.nist.secauto.metaschema.cli.processor.command;
+import gov.nist.secauto.metaschema.cli.processor.command.impl.DefaultExtraArgument;
+
+import edu.umd.cs.findbugs.annotations.NonNull;
+
+/**
+ * A representation of an extra, non-option command line argument.
+ */
public interface ExtraArgument {
+ /**
+ * Create a new extra argument instance.
+ *
+ * @param name
+ * the argument name
+ * @param required
+ * {@code true} if the argument is required, or {@code false} otherwise
+ * @return the instance
+ */
+ @NonNull
+ static ExtraArgument newInstance(@NonNull String name, boolean required) {
+ if (name.isBlank()) {
+ throw new IllegalArgumentException("name cannot be empty or blank");
+ }
+ return new DefaultExtraArgument(name, required);
+ }
+
+ /**
+ * Get the argument name.
+ *
+ * @return the name
+ */
String getName();
+ /**
+ * Get if the argument is required.
+ *
+ * @return {@code true} if the argument is required, or {@code false} otherwise
+ */
boolean isRequired();
/**
- * The allowed number of arguments of this type.
+ * Get the allow number of arguments of this type.
*
- * @return a positive integer value
+ * @return the allowed number of arguments as a positive number or {@code -1}
+ * for unlimited
*/
- int getNumber();
+ default int getNumber() {
+ return 1;
+ }
}
diff --git a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/ICommand.java b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/ICommand.java
index 854c2a1ba..4ebdd9ac9 100644
--- a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/ICommand.java
+++ b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/ICommand.java
@@ -14,51 +14,174 @@
import java.util.Collection;
import java.util.List;
+import java.util.stream.Collectors;
import edu.umd.cs.findbugs.annotations.NonNull;
+import edu.umd.cs.findbugs.annotations.Nullable;
+/**
+ * A command line interface command.
+ */
public interface ICommand {
+ /**
+ * Get the name of the command.
+ *
+ * This name is used to call the command as a command line argument.
+ *
+ * @return the command's name
+ */
@NonNull
String getName();
+ /**
+ * Get a description of what the command does.
+ *
+ * This description is displayed in help output.
+ *
+ * @return the description
+ */
@NonNull
String getDescription();
+ /**
+ * Get the non-option arguments.
+ *
+ * @return the arguments, or an empty list if there are no arguments
+ */
@NonNull
default List getExtraArguments() {
return CollectionUtil.emptyList();
}
- default int requiredExtraArgumentsCount() {
- return (int) getExtraArguments().stream()
- .filter(ExtraArgument::isRequired)
- .count();
- }
-
+ /**
+ * Used to gather options directly associated with this command.
+ *
+ * @return the options
+ */
@NonNull
default Collection extends Option> gatherOptions() {
// by default there are no options to handle
return CollectionUtil.emptyList();
}
+ /**
+ * Get any sub-commands associated with this command.
+ *
+ * @return the sub-commands
+ */
@NonNull
- Collection getSubCommands();
-
- boolean isSubCommandRequired();
+ default Collection getSubCommands() {
+ // no sub-commands by default
+ return CollectionUtil.emptyList();
+ }
- @SuppressWarnings("unused")
+ /**
+ * Get a sub-command by it's command name.
+ *
+ * @param name
+ * the requested sub-command name
+ * @return the command or {@code null} if no sub-command exists with that name
+ */
+ @Nullable
default ICommand getSubCommandByName(@NonNull String name) {
- // no sub commands by default
+ // no sub-commands by default
return null;
}
- @SuppressWarnings("unused")
+ /**
+ * Determine if this command requires the use of a sub-command.
+ *
+ * @return {@code true} if a sub-command is required or {@code false} otherwise
+ */
+ default boolean isSubCommandRequired() {
+ // no sub-commands by default
+ return false;
+ }
+
+ /**
+ * Validate the options provided on the command line based on what is required
+ * for this command.
+ *
+ * @param callingContext
+ * the context of the command execution
+ * @param commandLine
+ * the parsed command line details
+ * @throws InvalidArgumentException
+ * if a problem was found while validating the options
+ */
default void validateOptions(
@NonNull CallingContext callingContext,
- @NonNull CommandLine cmdLine) throws InvalidArgumentException {
+ @NonNull CommandLine commandLine) throws InvalidArgumentException {
// by default there are no options to handle
}
+ /**
+ * Create a new executor for this command.
+ *
+ * @param callingContext
+ * the context of the command execution
+ * @param commandLine
+ * the parsed command line details
+ * @return the executor
+ */
@NonNull
- ICommandExecutor newExecutor(@NonNull CallingContext callingContext, @NonNull CommandLine cmdLine);
+ ICommandExecutor newExecutor(
+ @NonNull CallingContext callingContext,
+ @NonNull CommandLine commandLine);
+
+ /**
+ * Validates that the provided extra arguments meet expectations.
+ *
+ * @param callingContext
+ * the context of the command execution
+ * @param commandLine
+ * the parsed command line details
+ * @throws InvalidArgumentException
+ * if a problem was found while validating the extra arguments
+ */
+ default void validateExtraArguments(
+ @NonNull CallingContext callingContext,
+ @NonNull CommandLine commandLine)
+ throws InvalidArgumentException {
+
+ validateSubCommandRequirement();
+ validateArgumentCount(commandLine);
+ validateRequiredArguments(commandLine);
+ }
+
+ private void validateSubCommandRequirement() throws InvalidArgumentException {
+ if (isSubCommandRequired()) {
+ throw new InvalidArgumentException("Please choose a valid sub-command.");
+ }
+ }
+
+ private void validateArgumentCount(@NonNull CommandLine commandLine) throws InvalidArgumentException {
+ List extraArguments = getExtraArguments();
+ int maxArguments = extraArguments.size();
+ List actualArgs = commandLine.getArgList();
+
+ if (actualArgs.size() > maxArguments) {
+ throw new InvalidArgumentException(
+ String.format("Too many extra arguments provided. Expected at most %d, but got %d.",
+ maxArguments, actualArgs.size()));
+ }
+
+ }
+
+ private void validateRequiredArguments(@NonNull CommandLine commandLine) throws InvalidArgumentException {
+ List actualArgs = commandLine.getArgList();
+ List requiredExtraArguments = getExtraArguments().stream()
+ .filter(ExtraArgument::isRequired)
+ .collect(Collectors.toUnmodifiableList());
+
+ if (actualArgs.size() < requiredExtraArguments.size()) {
+ throw new InvalidArgumentException(
+ String.format("Missing required arguments: %s. Expected %d required arguments, but got %d.",
+ requiredExtraArguments.stream()
+ .map(arg -> "<" + arg.getName() + ">")
+ .collect(Collectors.joining(" ")),
+ requiredExtraArguments.size(),
+ actualArgs.size()));
+ }
+ }
}
diff --git a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/ICommandExecutor.java b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/ICommandExecutor.java
index 342d0498a..92b3acc65 100644
--- a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/ICommandExecutor.java
+++ b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/ICommandExecutor.java
@@ -11,9 +11,33 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * An abstract base class that implements the {@link ICommandExecutor}
+ * interface, providing common functionality for command execution
+ * implementations. Concrete subclasses must implement the {@link #execute()}
+ * method to define specific command behavior.
+ */
public interface ICommandExecutor {
+ /**
+ * Execute the command operation.
+ *
+ * @throws CommandExecutionException
+ * if an error occurred while executing the command operation
+ */
void execute() throws CommandExecutionException;
+ /**
+ * Create a new command executor.
+ *
+ * @param callingContext
+ * the context of the command execution
+ * @param commandLine
+ * the parsed command line details
+ * @param function
+ * a function that accepts a calling context and command line
+ * information
+ * @return the executor instance
+ */
@NonNull
static ICommandExecutor using(
@NonNull CallingContext callingContext,
@@ -22,8 +46,22 @@ static ICommandExecutor using(
return () -> function.execute(callingContext, commandLine);
}
+ /**
+ * This functional interface represents a method that is used to execute a
+ * command operation.
+ */
@FunctionalInterface
interface ExecutionFunction {
+ /**
+ * Execute a command operation.
+ *
+ * @param callingContext
+ * the context of the command execution
+ * @param commandLine
+ * the parsed command line details
+ * @throws CommandExecutionException
+ * if an error occurred while executing the command operation
+ */
void execute(
@NonNull CallingContext callingContext,
@NonNull CommandLine commandLine) throws CommandExecutionException;
diff --git a/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/impl/DefaultExtraArgument.java b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/impl/DefaultExtraArgument.java
new file mode 100644
index 000000000..d9afe6e0d
--- /dev/null
+++ b/cli-processor/src/main/java/gov/nist/secauto/metaschema/cli/processor/command/impl/DefaultExtraArgument.java
@@ -0,0 +1,46 @@
+/*
+ * SPDX-FileCopyrightText: none
+ * SPDX-License-Identifier: CC0-1.0
+ */
+
+package gov.nist.secauto.metaschema.cli.processor.command.impl;
+
+import gov.nist.secauto.metaschema.cli.processor.command.ExtraArgument;
+
+import edu.umd.cs.findbugs.annotations.NonNull;
+
+/**
+ * A default implementation of the {@link ExtraArgument} interface that
+ * represents a named command-line argument which can be marked as required or
+ * optional.
+ *
+ * This implementation is used by the command processor to handle additional
+ * arguments that are not covered by specific command options.
+ */
+public class DefaultExtraArgument implements ExtraArgument {
+ private final String name;
+ private final boolean required;
+
+ /**
+ * Construct a new instance.
+ *
+ * @param name
+ * the argument name
+ * @param required
+ * {@code true} if the argument is required, or {@code false} otherwise
+ */
+ public DefaultExtraArgument(@NonNull String name, boolean required) {
+ this.name = name;
+ this.required = required;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean isRequired() {
+ return required;
+ }
+}
diff --git a/cli-processor/src/main/resources/log4j2.xml b/cli-processor/src/main/resources/log4j2.xml
index 758bf2a4c..99656348f 100644
--- a/cli-processor/src/main/resources/log4j2.xml
+++ b/cli-processor/src/main/resources/log4j2.xml
@@ -3,11 +3,16 @@
-
+
-
+
+
+
+
+
+
@@ -16,7 +21,12 @@
-
+
+
+
+
+
+
diff --git a/core/src/main/java-templates/gov/nist/secauto/metaschema/core/MetaschemaJavaVersion.java b/core/src/main/java-templates/gov/nist/secauto/metaschema/core/MetaschemaJavaVersion.java
index c81c8f95e..249d760ce 100644
--- a/core/src/main/java-templates/gov/nist/secauto/metaschema/core/MetaschemaJavaVersion.java
+++ b/core/src/main/java-templates/gov/nist/secauto/metaschema/core/MetaschemaJavaVersion.java
@@ -3,15 +3,21 @@
import gov.nist.secauto.metaschema.core.util.IVersionInfo;
+/**
+ * Provides version information for this library.
+ *
+ * This class exposes build-time metadata including version numbers, build
+ * timestamps, and Git repository information.
+ */
public class MetaschemaJavaVersion implements IVersionInfo {
- public static final String NAME = "metaschema-java";
- public static final String VERSION = "${project.version}";
- public static final String BUILD_TIMESTAMP = "${timestamp}";
- public static final String COMMIT = "@git.commit.id.abbrev@";
- public static final String BRANCH = "@git.branch@";
- public static final String CLOSEST_TAG = "@git.closest.tag.name@";
- public static final String ORIGIN = "@git.remote.origin.url@";
+ private static final String NAME = "metaschema-java";
+ private static final String VERSION = "${project.version}";
+ private static final String BUILD_TIMESTAMP = "${timestamp}";
+ private static final String COMMIT = "@git.commit.id.abbrev@";
+ private static final String BRANCH = "@git.branch@";
+ private static final String CLOSEST_TAG = "@git.closest.tag.name@";
+ private static final String ORIGIN = "@git.remote.origin.url@";
@Override
public String getName() {
diff --git a/core/src/main/java-templates/gov/nist/secauto/metaschema/core/model/MetaschemaVersion.java b/core/src/main/java-templates/gov/nist/secauto/metaschema/core/model/MetaschemaVersion.java
index a6bb77c6c..942731fda 100644
--- a/core/src/main/java-templates/gov/nist/secauto/metaschema/core/model/MetaschemaVersion.java
+++ b/core/src/main/java-templates/gov/nist/secauto/metaschema/core/model/MetaschemaVersion.java
@@ -4,15 +4,18 @@
import gov.nist.secauto.metaschema.core.util.IVersionInfo;
+/**
+ * Provides version information for the underlying Metaschema implementation used by this library.
+ */
public class MetaschemaVersion implements IVersionInfo {
- public static final String NAME = "metaschema";
- public static final String BUILD_VERSION = "${project.version}";
- public static final String BUILD_TIMESTAMP = "${timestamp}";
- public static final String COMMIT = "@metaschema-git.commit.id.abbrev@";
- public static final String BRANCH = "@metaschema-git.branch@";
- public static final String CLOSEST_TAG = "@metaschema-git.closest.tag.name@";
- public static final String ORIGIN = "@metaschema-git.remote.origin.url@";
+ private static final String NAME = "metaschema";
+ private static final String BUILD_VERSION = "${project.version}";
+ private static final String BUILD_TIMESTAMP = "${timestamp}";
+ private static final String COMMIT = "@metaschema-git.commit.id.abbrev@";
+ private static final String BRANCH = "@metaschema-git.branch@";
+ private static final String CLOSEST_TAG = "@metaschema-git.closest.tag.name@";
+ private static final String ORIGIN = "@metaschema-git.remote.origin.url@";
@Override
public String getName() {
@@ -21,7 +24,7 @@ public String getName() {
@Override
public String getVersion() {
- return CLOSEST_TAG;
+ return BUILD_VERSION;
}
@Override
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/MetaschemaConstants.java b/core/src/main/java/gov/nist/secauto/metaschema/core/MetaschemaConstants.java
index 0456bd903..43ad55978 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/MetaschemaConstants.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/MetaschemaConstants.java
@@ -11,6 +11,9 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * A collection of constant values related to Metaschema handling.
+ */
public final class MetaschemaConstants {
/**
* This is the namespace used by Metaschema in formats that require or use a
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/AbstractCustomJavaDataTypeAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/AbstractCustomJavaDataTypeAdapter.java
index 409cf786a..b5e81cdc9 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/AbstractCustomJavaDataTypeAdapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/AbstractCustomJavaDataTypeAdapter.java
@@ -43,5 +43,4 @@ public TYPE copy(Object obj) {
// method.
return ((TYPE) obj).copy();
}
-
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/AbstractDataTypeAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/AbstractDataTypeAdapter.java
index 8f6fd6178..25f306bfc 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/AbstractDataTypeAdapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/AbstractDataTypeAdapter.java
@@ -8,7 +8,6 @@
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
-import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem;
import gov.nist.secauto.metaschema.core.model.util.JsonUtil;
import gov.nist.secauto.metaschema.core.model.util.XmlEventUtil;
@@ -197,46 +196,4 @@ public void writeJsonValue(Object value, JsonGenerator generator) throws IOExcep
@Override
public abstract ITEM_TYPE newItem(Object value);
-
- @SuppressWarnings("unchecked")
- @Override
- public ITEM_TYPE cast(IAnyAtomicItem item) {
- if (item == null) {
- throw new InvalidValueForCastFunctionException("item is null");
- }
- return getItemClass().isAssignableFrom(item.getClass())
- ? (ITEM_TYPE) item
- : castInternal(item);
- }
-
- /**
- * Attempt to cast the provided item to this adapter's item type.
- *
- * The default implementation of this will attempt to parse the provided item as
- * a string using the {@link #parse(String)} method. If this behavior is
- * undesirable, then a subclass should override this method.
- *
- * @param item
- * the item to cast
- * @return the item casted to this adapter's item type
- * @throws InvalidValueForCastFunctionException
- * if the casting of the item is not possible because the item
- * represents an invalid value for this adapter's item type
- */
- @NonNull
- protected ITEM_TYPE castInternal(@NonNull IAnyAtomicItem item) {
- // try string based casting as a fallback
- String itemString;
- try {
- itemString = item.asString();
- TYPE value = parse(itemString);
- return newItem(value);
- } catch (IllegalArgumentException | IllegalStateException ex) {
- throw new InvalidValueForCastFunctionException(
- String.format("The value '%s' is not compatible with the type '%s'",
- item.getValue(),
- getItemClass().getName()),
- ex);
- }
- }
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/IDataTypeAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/IDataTypeAdapter.java
index 83a8183e9..2fb732997 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/IDataTypeAdapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/IDataTypeAdapter.java
@@ -9,7 +9,6 @@
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes;
-import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
@@ -137,25 +136,9 @@ default boolean isAtomic() {
* the item's value
* @return a new item
*/
- // TODO: markup types are not atomic values.
- // Figure out a better base type (i.e., IValuedItem)
- // TODO: move to IAnyAtomicItem
@NonNull
IAnyAtomicItem newItem(@NonNull Object value);
- /**
- * Cast the provided item to an item of this type, if possible.
- *
- * @param item
- * the atomic item to cast
- * @return an atomic item of this type
- * @throws InvalidValueForCastFunctionException
- * if the provided item type cannot be cast to this item type
- */
- // TODO: move to IAnyAtomicItem
- @NonNull
- IAnyAtomicItem cast(IAnyAtomicItem item);
-
/**
* Determines if adapter can parse the next element. The next element's
* {@link QName} is provided for this purpose.
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/AbstractIntegerAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/AbstractIntegerAdapter.java
index 7dd52be02..721fcfadc 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/AbstractIntegerAdapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/AbstractIntegerAdapter.java
@@ -39,7 +39,11 @@ public JsonFormatTypes getJsonRawType() {
@Override
public BigInteger parse(String value) {
- return new BigInteger(value);
+ try {
+ return new BigInteger(value);
+ } catch (NumberFormatException ex) {
+ throw new IllegalArgumentException(ex);
+ }
}
@Override
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/Base64Adapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/Base64Adapter.java
index 7bcef4b6f..8c4772744 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/Base64Adapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/Base64Adapter.java
@@ -20,6 +20,11 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * Support for the Metaschema base64
+ * data type.
+ */
public class Base64Adapter
extends AbstractDataTypeAdapter {
@NonNull
@@ -43,30 +48,39 @@ public JsonFormatTypes getJsonRawType() {
return JsonFormatTypes.STRING;
}
- @SuppressWarnings("null")
@Override
public ByteBuffer parse(String value) {
Base64.Decoder decoder = Base64.getDecoder();
byte[] result = decoder.decode(value);
- return ByteBuffer.wrap(result);
+ return ObjectUtils.notNull(ByteBuffer.wrap(result));
}
@Override
public ByteBuffer copy(Object obj) {
ByteBuffer buffer = (ByteBuffer) obj;
- final ByteBuffer clone
- = buffer.isDirect() ? ByteBuffer.allocateDirect(buffer.capacity()) : ByteBuffer.allocate(buffer.capacity());
- final ByteBuffer readOnlyCopy = buffer.asReadOnlyBuffer();
+ ByteBuffer clone = buffer.isDirect()
+ ? ByteBuffer.allocateDirect(buffer.capacity())
+ : ByteBuffer.allocate(buffer.capacity());
+ ByteBuffer readOnlyCopy = buffer.asReadOnlyBuffer();
readOnlyCopy.flip();
clone.put(readOnlyCopy);
return clone;
}
- @SuppressWarnings("null")
@Override
public String asString(Object value) {
+ ByteBuffer buffer = (ByteBuffer) value;
+ byte[] array;
+ if (buffer.hasArray()) {
+ array = buffer.array();
+ } else {
+ // Handle direct buffers
+ array = new byte[buffer.remaining()];
+ buffer.get(array);
+ }
+
Base64.Encoder encoder = Base64.getEncoder();
- return encoder.encodeToString(((ByteBuffer) value).array());
+ return ObjectUtils.notNull(encoder.encodeToString(array));
}
@Override
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/BooleanAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/BooleanAdapter.java
index b0336a405..f39cd0363 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/BooleanAdapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/BooleanAdapter.java
@@ -11,11 +11,7 @@
import gov.nist.secauto.metaschema.core.datatype.AbstractDataTypeAdapter;
import gov.nist.secauto.metaschema.core.metapath.MetapathConstants;
-import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
-import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IBooleanItem;
-import gov.nist.secauto.metaschema.core.metapath.item.atomic.INumericItem;
-import gov.nist.secauto.metaschema.core.metapath.item.atomic.IStringItem;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
import java.io.IOException;
@@ -92,57 +88,4 @@ public IBooleanItem newItem(Object value) {
return IBooleanItem.valueOf(item);
}
- @Override
- protected IBooleanItem castInternal(@NonNull IAnyAtomicItem item) {
- IBooleanItem retval;
- if (item instanceof INumericItem) {
- retval = castToBoolean((INumericItem) item);
- } else if (item instanceof IStringItem) {
- retval = castToBoolean((IStringItem) item);
- } else {
- try {
- retval = castToBoolean(item.asStringItem());
- } catch (IllegalStateException ex) {
- throw new InvalidValueForCastFunctionException(ex.getLocalizedMessage(), ex);
- }
- }
- return retval;
- }
-
- /**
- * Cast the provided numeric value to a boolean. Any non-zero value will be
- * {@code true}, or {@code false} otherwise.
- *
- * @param item
- * the item to cast
- * @return {@code true} if the item value is non-zero, or {@code false}
- * otherwise
- */
- @NonNull
- protected IBooleanItem castToBoolean(@NonNull INumericItem item) {
- return IBooleanItem.valueOf(item.toEffectiveBoolean());
- }
-
- /**
- * If the string is a numeric value, treat it as so. Otherwise parse the value
- * as a boolean string.
- *
- * @param item
- * the item to cast
- * @return the effective boolean value of the string
- * @throws InvalidValueForCastFunctionException
- * if the provided item cannot be cast to a boolean value by any means
- */
- @NonNull
- protected IBooleanItem castToBoolean(@NonNull IStringItem item) {
- IBooleanItem retval;
- try {
- INumericItem numeric = INumericItem.cast(item);
- retval = castToBoolean(numeric);
- } catch (InvalidValueForCastFunctionException ex) {
- retval = super.castInternal(item);
- }
- return retval;
- }
-
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/DateAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/DateAdapter.java
index d8191f8be..ab2c79799 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/DateAdapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/DateAdapter.java
@@ -8,14 +8,9 @@
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes;
import gov.nist.secauto.metaschema.core.datatype.AbstractCustomJavaDataTypeAdapter;
-import gov.nist.secauto.metaschema.core.datatype.object.Date;
+import gov.nist.secauto.metaschema.core.datatype.object.AmbiguousDate;
import gov.nist.secauto.metaschema.core.metapath.MetapathConstants;
-import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
-import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IDateItem;
-import gov.nist.secauto.metaschema.core.metapath.item.atomic.IDateTimeItem;
-import gov.nist.secauto.metaschema.core.metapath.item.atomic.IStringItem;
-import gov.nist.secauto.metaschema.core.metapath.item.atomic.IUntypedAtomicItem;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
import java.time.LocalDate;
@@ -32,21 +27,28 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * Support for the Metaschema date
+ * data type.
+ */
public class DateAdapter
- extends AbstractCustomJavaDataTypeAdapter {
+ extends AbstractCustomJavaDataTypeAdapter {
@NonNull
private static final List NAMES = ObjectUtils.notNull(
List.of(new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "date")));
- private static final Pattern DATE_TIMEZONE = Pattern.compile("^("
- + "^(?:(?:2000|2400|2800|(?:19|2[0-9](?:0[48]|[2468][048]|[13579][26])))-02-29)"
- + "|(?:(?:(?:19|2[0-9])[0-9]{2})-02-(?:0[1-9]|1[0-9]|2[0-8]))"
- + "|(?:(?:(?:19|2[0-9])[0-9]{2})-(?:0[13578]|10|12)-(?:0[1-9]|[12][0-9]|3[01]))"
- + "|(?:(?:(?:19|2[0-9])[0-9]{2})-(?:0[469]|11)-(?:0[1-9]|[12][0-9]|30))"
- + ")"
- + "(Z|[+-][0-9]{2}:[0-9]{2})?$");
+ @NonNull
+ private static final Pattern DATE_TIMEZONE = ObjectUtils.notNull(
+ Pattern.compile("^("
+ + "^(?:(?:2000|2400|2800|(?:19|2[0-9](?:0[48]|[2468][048]|[13579][26])))-02-29)"
+ + "|(?:(?:(?:19|2[0-9])[0-9]{2})-02-(?:0[1-9]|1[0-9]|2[0-8]))"
+ + "|(?:(?:(?:19|2[0-9])[0-9]{2})-(?:0[13578]|10|12)-(?:0[1-9]|[12][0-9]|3[01]))"
+ + "|(?:(?:(?:19|2[0-9])[0-9]{2})-(?:0[469]|11)-(?:0[1-9]|[12][0-9]|30))"
+ + ")"
+ + "(Z|[+-][0-9]{2}:[0-9]{2})?$"));
DateAdapter() {
- super(Date.class);
+ super(AmbiguousDate.class);
}
@Override
@@ -60,7 +62,7 @@ public JsonFormatTypes getJsonRawType() {
}
@Override
- public Date parse(String value) {
+ public AmbiguousDate parse(String value) {
Matcher matcher = DATE_TIMEZONE.matcher(value);
if (!matcher.matches()) {
throw new IllegalArgumentException("Invalid date: " + value);
@@ -70,12 +72,12 @@ public Date parse(String value) {
= String.format("%sT00:00:00%s", matcher.group(1), matcher.group(2) == null ? "" : matcher.group(2));
try {
TemporalAccessor accessor = DateFormats.DATE_TIME_WITH_TZ.parse(parseValue);
- return new Date(ObjectUtils.notNull(ZonedDateTime.from(accessor)), true); // NOPMD - readability
+ return new AmbiguousDate(ObjectUtils.notNull(ZonedDateTime.from(accessor)), true); // NOPMD - readability
} catch (DateTimeParseException ex) {
try {
TemporalAccessor accessor = DateFormats.DATE_TIME_WITHOUT_TZ.parse(parseValue);
LocalDate date = LocalDate.from(accessor);
- return new Date(ObjectUtils.notNull(ZonedDateTime.of(date, LocalTime.MIN, ZoneOffset.UTC)), false);
+ return new AmbiguousDate(ObjectUtils.notNull(ZonedDateTime.of(date, LocalTime.MIN, ZoneOffset.UTC)), false);
} catch (DateTimeParseException ex2) {
IllegalArgumentException newEx = new IllegalArgumentException(ex2.getLocalizedMessage(), ex2);
newEx.addSuppressed(ex);
@@ -86,20 +88,10 @@ public Date parse(String value) {
@Override
public String asString(Object obj) {
- Date value = (Date) obj;
- String retval;
- if (value.hasTimeZone()) {
- @SuppressWarnings("null")
- @NonNull
- String formatted = DateFormats.DATE_WITH_TZ.format(value.getValue());
- retval = formatted;
- } else {
- @SuppressWarnings("null")
- @NonNull
- String formatted = DateFormats.DATE_WITHOUT_TZ.format(value.getValue());
- retval = formatted;
- }
- return retval;
+ AmbiguousDate value = (AmbiguousDate) obj;
+ return ObjectUtils.notNull(value.hasTimeZone()
+ ? DateFormats.DATE_WITH_TZ.format(value.getValue())
+ : DateFormats.DATE_WITHOUT_TZ.format(value.getValue()));
}
@Override
@@ -109,23 +101,7 @@ public Class getItemClass() {
@Override
public IDateItem newItem(Object value) {
- Date item = toValue(value);
+ AmbiguousDate item = toValue(value);
return IDateItem.valueOf(item);
}
-
- @Override
- @NonNull
- protected IDateItem castInternal(@NonNull IAnyAtomicItem item) {
- IDateItem retval;
- if (item instanceof IDateTimeItem) {
- ZonedDateTime value = ((IDateTimeItem) item).asZonedDateTime();
- retval = IDateItem.valueOf(value);
- } else if (item instanceof IStringItem || item instanceof IUntypedAtomicItem) {
- retval = super.castInternal(item);
- } else {
- throw new InvalidValueForCastFunctionException(
- String.format("unsupported item type '%s'", item.getClass().getName()));
- }
- return retval;
- }
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/DateTimeAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/DateTimeAdapter.java
index 32cb0b385..6d61a4e55 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/DateTimeAdapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/DateTimeAdapter.java
@@ -8,14 +8,9 @@
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes;
import gov.nist.secauto.metaschema.core.datatype.AbstractCustomJavaDataTypeAdapter;
-import gov.nist.secauto.metaschema.core.datatype.object.DateTime;
+import gov.nist.secauto.metaschema.core.datatype.object.AmbiguousDateTime;
import gov.nist.secauto.metaschema.core.metapath.MetapathConstants;
-import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
-import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem;
-import gov.nist.secauto.metaschema.core.metapath.item.atomic.IDateItem;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IDateTimeItem;
-import gov.nist.secauto.metaschema.core.metapath.item.atomic.IStringItem;
-import gov.nist.secauto.metaschema.core.metapath.item.atomic.IUntypedAtomicItem;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
import java.time.LocalDateTime;
@@ -28,8 +23,13 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * Support for the Metaschema date-time
+ * data type.
+ */
public class DateTimeAdapter
- extends AbstractCustomJavaDataTypeAdapter {
+ extends AbstractCustomJavaDataTypeAdapter {
@NonNull
private static final List NAMES = ObjectUtils.notNull(
List.of(
@@ -38,7 +38,7 @@ public class DateTimeAdapter
new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "dateTime")));
DateTimeAdapter() {
- super(DateTime.class);
+ super(AmbiguousDateTime.class);
}
@Override
@@ -51,39 +51,44 @@ public JsonFormatTypes getJsonRawType() {
return JsonFormatTypes.STRING;
}
- @SuppressWarnings("null")
@Override
- public DateTime parse(String value) {
+ public AmbiguousDateTime parse(String value) {
+ AmbiguousDateTime retval;
try {
- return new DateTime(ZonedDateTime.from(DateFormats.DATE_TIME_WITH_TZ.parse(value)), true); // NOPMD - readability
+ retval = parseWithTimeZone(value);
} catch (DateTimeParseException ex) {
try {
- LocalDateTime dateTime = LocalDateTime.from(DateFormats.DATE_TIME_WITHOUT_TZ.parse(value));
- return new DateTime(ZonedDateTime.of(dateTime, ZoneOffset.UTC), false);
+ retval = parseWithoutTimeZone(value);
} catch (DateTimeParseException ex2) {
IllegalArgumentException newEx = new IllegalArgumentException(ex2.getLocalizedMessage(), ex2);
newEx.addSuppressed(ex);
- throw newEx; // NOPMD - it's ok
+ throw newEx;
}
}
+ return retval;
+ }
+
+ @NonNull
+ private static AmbiguousDateTime parseWithTimeZone(@NonNull String value) {
+ return new AmbiguousDateTime(
+ ObjectUtils.notNull(ZonedDateTime.from(DateFormats.DATE_TIME_WITH_TZ.parse(value))),
+ true);
+ }
+
+ @NonNull
+ private static AmbiguousDateTime parseWithoutTimeZone(@NonNull String value) {
+ LocalDateTime dateTime = LocalDateTime.from(DateFormats.DATE_TIME_WITHOUT_TZ.parse(value));
+ return new AmbiguousDateTime(
+ ObjectUtils.notNull(ZonedDateTime.of(dateTime, ZoneOffset.UTC)),
+ false);
}
@Override
public String asString(Object obj) {
- DateTime value = (DateTime) obj;
- String retval;
- if (value.hasTimeZone()) {
- @SuppressWarnings("null")
- @NonNull
- String formatted = DateFormats.DATE_TIME_WITH_TZ.format(value.getValue());
- retval = formatted;
- } else {
- @SuppressWarnings("null")
- @NonNull
- String formatted = DateFormats.DATE_TIME_WITHOUT_TZ.format(value.getValue());
- retval = formatted;
- }
- return retval;
+ AmbiguousDateTime value = (AmbiguousDateTime) obj;
+ return ObjectUtils.notNull(value.hasTimeZone()
+ ? DateFormats.DATE_TIME_WITH_TZ.format(value.getValue())
+ : DateFormats.DATE_TIME_WITHOUT_TZ.format(value.getValue()));
}
@Override
@@ -93,23 +98,7 @@ public Class getItemClass() {
@Override
public IDateTimeItem newItem(Object value) {
- DateTime item = toValue(value);
+ AmbiguousDateTime item = toValue(value);
return IDateTimeItem.valueOf(item);
}
-
- @Override
- protected IDateTimeItem castInternal(@NonNull IAnyAtomicItem item) {
- // TODO: bring up to spec
- IDateTimeItem retval;
- if (item instanceof IDateItem) {
- retval = IDateTimeItem.valueOf(((IDateItem) item).asZonedDateTime());
- } else if (item instanceof IStringItem || item instanceof IUntypedAtomicItem) {
- retval = super.castInternal(item);
- } else {
- throw new InvalidValueForCastFunctionException(
- String.format("unsupported item type '%s'", item.getClass().getName()));
- }
- return retval;
- }
-
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/DateTimeWithTZAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/DateTimeWithTZAdapter.java
index d928d0bae..3c1c0f4d9 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/DateTimeWithTZAdapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/DateTimeWithTZAdapter.java
@@ -21,6 +21,11 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * Support for the Metaschema date-time-with-timezone
+ * data type.
+ */
public class DateTimeWithTZAdapter
extends AbstractDataTypeAdapter {
@NonNull
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/DateWithTZAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/DateWithTZAdapter.java
index 5e16e7854..f309d20d7 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/DateWithTZAdapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/DateWithTZAdapter.java
@@ -23,6 +23,11 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * Support for the Metaschema date-with-timezone
+ * data type.
+ */
public class DateWithTZAdapter
extends AbstractDataTypeAdapter {
@NonNull
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/DayTimeAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/DayTimeAdapter.java
index 5f9ca4348..6632ab70b 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/DayTimeAdapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/DayTimeAdapter.java
@@ -20,6 +20,11 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * Support for the Metaschema day-time-duration
+ * data type.
+ */
public class DayTimeAdapter
extends AbstractDataTypeAdapter {
@NonNull
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/DecimalAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/DecimalAdapter.java
index 52169723e..25667eb66 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/DecimalAdapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/DecimalAdapter.java
@@ -10,10 +10,7 @@
import gov.nist.secauto.metaschema.core.datatype.AbstractDataTypeAdapter;
import gov.nist.secauto.metaschema.core.metapath.MetapathConstants;
-import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem;
-import gov.nist.secauto.metaschema.core.metapath.item.atomic.IBooleanItem;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IDecimalItem;
-import gov.nist.secauto.metaschema.core.metapath.item.atomic.INumericItem;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
import java.io.IOException;
@@ -25,13 +22,14 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * Support for the Metaschema decimal
+ * data type.
+ */
public class DecimalAdapter
extends AbstractDataTypeAdapter {
- public static final MathContext MATH_CONTEXT = MathContext.DECIMAL64;
- @NonNull
- private static final BigDecimal DECIMAL_BOOLEAN_TRUE = new BigDecimal("1.0");
- @NonNull
- private static final BigDecimal DECIMAL_BOOLEAN_FALSE = new BigDecimal("0.0");
+ private static final MathContext MATH_CONTEXT = MathContext.DECIMAL64;
@NonNull
private static final List NAMES = ObjectUtils.notNull(
List.of(new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "decimal")));
@@ -80,18 +78,4 @@ public IDecimalItem newItem(Object value) {
BigDecimal item = toValue(value);
return IDecimalItem.valueOf(item);
}
-
- @Override
- protected IDecimalItem castInternal(@NonNull IAnyAtomicItem item) {
- IDecimalItem retval;
- if (item instanceof INumericItem) {
- retval = newItem(((INumericItem) item).asDecimal());
- } else if (item instanceof IBooleanItem) {
- boolean value = ((IBooleanItem) item).toBoolean();
- retval = newItem(value ? DECIMAL_BOOLEAN_TRUE : DECIMAL_BOOLEAN_FALSE);
- } else {
- retval = super.castInternal(item);
- }
- return retval;
- }
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/EmailAddressAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/EmailAddressAdapter.java
index 982325aec..35b128459 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/EmailAddressAdapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/EmailAddressAdapter.java
@@ -15,6 +15,11 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * Support for the Metaschema email-address
+ * data type.
+ */
public class EmailAddressAdapter
extends AbstractStringAdapter {
@NonNull
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/HostnameAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/HostnameAdapter.java
index 51feb78d7..ab79caf20 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/HostnameAdapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/HostnameAdapter.java
@@ -15,6 +15,11 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * Support for the Metaschema hostname
+ * data type.
+ */
public class HostnameAdapter
extends AbstractStringAdapter {
@NonNull
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/IPv4AddressAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/IPv4AddressAdapter.java
index 123a1ab27..d62023fe5 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/IPv4AddressAdapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/IPv4AddressAdapter.java
@@ -23,6 +23,11 @@
import inet.ipaddr.IncompatibleAddressException;
import inet.ipaddr.ipv4.IPv4Address;
+/**
+ * Support for the Metaschema ip-v4-address
+ * data type.
+ */
public class IPv4AddressAdapter
extends AbstractDataTypeAdapter {
@NonNull
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/IPv6AddressAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/IPv6AddressAdapter.java
index 324927f63..d7642d6cd 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/IPv6AddressAdapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/IPv6AddressAdapter.java
@@ -23,6 +23,11 @@
import inet.ipaddr.IncompatibleAddressException;
import inet.ipaddr.ipv6.IPv6Address;
+/**
+ * Support for the Metaschema ip-v6-address
+ * data type.
+ */
public class IPv6AddressAdapter
extends AbstractDataTypeAdapter {
@NonNull
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/IntegerAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/IntegerAdapter.java
index f77e74630..b6634c120 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/IntegerAdapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/IntegerAdapter.java
@@ -6,10 +6,7 @@
package gov.nist.secauto.metaschema.core.datatype.adapter;
import gov.nist.secauto.metaschema.core.metapath.MetapathConstants;
-import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem;
-import gov.nist.secauto.metaschema.core.metapath.item.atomic.IBooleanItem;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IIntegerItem;
-import gov.nist.secauto.metaschema.core.metapath.item.atomic.INumericItem;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
import java.math.BigInteger;
@@ -19,6 +16,11 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * Support for the Metaschema integer
+ * data type.
+ */
public class IntegerAdapter
extends AbstractIntegerAdapter {
@NonNull
@@ -45,18 +47,4 @@ public IIntegerItem newItem(Object value) {
BigInteger item = toValue(value);
return IIntegerItem.valueOf(item);
}
-
- @Override
- protected IIntegerItem castInternal(@NonNull IAnyAtomicItem item) {
- IIntegerItem retval;
- if (item instanceof INumericItem) {
- retval = newItem(((INumericItem) item).asInteger());
- } else if (item instanceof IBooleanItem) {
- boolean value = ((IBooleanItem) item).toBoolean();
- retval = newItem(ObjectUtils.notNull(value ? BigInteger.ONE : BigInteger.ZERO));
- } else {
- retval = super.castInternal(item);
- }
- return retval;
- }
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/MetaschemaDataTypeProvider.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/MetaschemaDataTypeProvider.java
index 6969a6cd7..bb91ba4f8 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/MetaschemaDataTypeProvider.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/MetaschemaDataTypeProvider.java
@@ -16,55 +16,165 @@
@SuppressWarnings("PMD.CouplingBetweenObjects")
public final class MetaschemaDataTypeProvider // NOPMD - Used for service initialization
extends AbstractDataTypeProvider {
+ /**
+ * The Metaschema base64
+ * data type instance.
+ */
@NonNull
public static final Base64Adapter BASE64 = new Base64Adapter();
+ /**
+ * The Metaschema boolean
+ * data type instance.
+ */
@NonNull
public static final BooleanAdapter BOOLEAN = new BooleanAdapter();
+ /**
+ * The Metaschema date
+ * data type instance.
+ */
@NonNull
public static final DateAdapter DATE = new DateAdapter();
+ /**
+ * The Metaschema date-with-timezone
+ * data type instance.
+ */
@NonNull
public static final DateWithTZAdapter DATE_WITH_TZ = new DateWithTZAdapter();
+ /**
+ * The Metaschema date-time
+ * data type instance.
+ */
@NonNull
public static final DateTimeAdapter DATE_TIME = new DateTimeAdapter();
+ /**
+ * The Metaschema date-time-with-timezone
+ * data type instance.
+ */
@NonNull
public static final DateTimeWithTZAdapter DATE_TIME_WITH_TZ = new DateTimeWithTZAdapter();
+ /**
+ * The Metaschema ip-v4-address
+ * data type instance.
+ */
@NonNull
public static final IPv4AddressAdapter IP_V4_ADDRESS = new IPv4AddressAdapter();
+ /**
+ * The Metaschema ip-v6-address
+ * data type instance.
+ */
@NonNull
public static final IPv6AddressAdapter IP_V6_ADDRESS = new IPv6AddressAdapter();
+ /**
+ * The Metaschema uri data
+ * type instance.
+ */
@NonNull
public static final UriAdapter URI = new UriAdapter();
+ /**
+ * The Metaschema uri-reference
+ * data type instance.
+ */
@NonNull
public static final UriReferenceAdapter URI_REFERENCE = new UriReferenceAdapter();
+ /**
+ * The Metaschema uuid
+ * data type instance.
+ */
@NonNull
public static final UuidAdapter UUID = new UuidAdapter();
-
+ /**
+ * The Metaschema day-time-duration
+ * data type instance.
+ */
@NonNull
public static final DayTimeAdapter DAY_TIME_DURATION = new DayTimeAdapter();
+ /**
+ * The Metaschema year-month-duration
+ * data type instance.
+ */
@NonNull
public static final YearMonthAdapter YEAR_MONTH_DURATION = new YearMonthAdapter();
-
+ /**
+ * The Metaschema decimal
+ * data type instance.
+ */
@NonNull
public static final DecimalAdapter DECIMAL = new DecimalAdapter();
+ /**
+ * The Metaschema integer
+ * data type instance.
+ */
@NonNull
public static final IntegerAdapter INTEGER = new IntegerAdapter();
+ /**
+ * The Metaschema non-negative-integer
+ * data type instance.
+ */
@NonNull
public static final NonNegativeIntegerAdapter NON_NEGATIVE_INTEGER = new NonNegativeIntegerAdapter();
+ /**
+ * The Metaschema positive-integer
+ * data type instance.
+ */
@NonNull
public static final PositiveIntegerAdapter POSITIVE_INTEGER = new PositiveIntegerAdapter();
-
+ /**
+ * The Metaschema email-address
+ * data type instance.
+ */
@NonNull
public static final EmailAddressAdapter EMAIL_ADDRESS = new EmailAddressAdapter();
+ /**
+ * The Metaschema hostname
+ * data type instance.
+ */
@NonNull
public static final HostnameAdapter HOSTNAME = new HostnameAdapter();
+ /**
+ * The Metaschema ncname
+ * data type instance.
+ */
@Deprecated(since = "0.7.0")
@NonNull
public static final NcNameAdapter NCNAME = new NcNameAdapter();
+ /**
+ * The Metaschema string
+ * data type instance.
+ */
@NonNull
public static final StringAdapter STRING = new StringAdapter();
+ /**
+ * The Metaschema token
+ * data type instance.
+ */
@NonNull
public static final TokenAdapter TOKEN = new TokenAdapter();
-
+ /**
+ * The default Metaschema data type instance to use when no data type is defined
+ * on a field or flag.
+ */
@NonNull
public static final StringAdapter DEFAULT_DATA_TYPE = STRING;
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/NcNameAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/NcNameAdapter.java
index 088a4d9da..143c98077 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/NcNameAdapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/NcNameAdapter.java
@@ -15,6 +15,11 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * Support for the Metaschema ncname
+ * data type.
+ */
@Deprecated(since = "0.7.0")
public class NcNameAdapter
extends AbstractStringAdapter {
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/NonNegativeIntegerAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/NonNegativeIntegerAdapter.java
index 15de6ff0a..9063bb00a 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/NonNegativeIntegerAdapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/NonNegativeIntegerAdapter.java
@@ -16,6 +16,11 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * Support for the Metaschema non-negative-integer
+ * data type.
+ */
public class NonNegativeIntegerAdapter
extends AbstractIntegerAdapter {
@NonNull
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/PositiveIntegerAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/PositiveIntegerAdapter.java
index 22db33056..a78141ed7 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/PositiveIntegerAdapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/PositiveIntegerAdapter.java
@@ -16,6 +16,11 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * Support for the Metaschema positive-integer
+ * data type.
+ */
public class PositiveIntegerAdapter
extends AbstractIntegerAdapter {
@NonNull
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/StringAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/StringAdapter.java
index 18b0e4d05..8c5373d74 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/StringAdapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/StringAdapter.java
@@ -15,6 +15,11 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * Support for the Metaschema string
+ * data type.
+ */
public class StringAdapter
extends AbstractStringAdapter {
@NonNull
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/TokenAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/TokenAdapter.java
index 39091f4d5..f7d9d42a6 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/TokenAdapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/TokenAdapter.java
@@ -15,6 +15,11 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * Support for the Metaschema token
+ * data type.
+ */
public class TokenAdapter
extends AbstractStringAdapter {
@NonNull
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/UriAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/UriAdapter.java
index 0ffb1afcc..fbeaa5137 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/UriAdapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/UriAdapter.java
@@ -19,6 +19,11 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * Support for the Metaschema uri data
+ * type.
+ */
public class UriAdapter
extends AbstractDataTypeAdapter {
@NonNull
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/UriReferenceAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/UriReferenceAdapter.java
index e51a4c6bd..92587d733 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/UriReferenceAdapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/UriReferenceAdapter.java
@@ -19,6 +19,11 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * Support for the Metaschema uri-reference
+ * data type.
+ */
public class UriReferenceAdapter
extends AbstractDataTypeAdapter {
@NonNull
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/UuidAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/UuidAdapter.java
index 4edaface0..33313265b 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/UuidAdapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/UuidAdapter.java
@@ -20,11 +20,20 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * Support for the Metaschema uuid
+ * data type.
+ */
public class UuidAdapter
extends AbstractDataTypeAdapter {
@NonNull
private static final List NAMES = ObjectUtils.notNull(
List.of(new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "uuid")));
+
+ /**
+ * A regular expression that matches a valid UUID.
+ */
public static final Pattern UUID_PATTERN
= Pattern.compile("^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[45][0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$");
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/YearMonthAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/YearMonthAdapter.java
index 518b70ead..7f1511adf 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/YearMonthAdapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/YearMonthAdapter.java
@@ -20,6 +20,11 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * Support for the Metaschema year-month-duration
+ * data type.
+ */
public class YearMonthAdapter
extends AbstractDataTypeAdapter {
@NonNull
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/AbstractMarkupAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/AbstractMarkupAdapter.java
index e745ea7d3..b4f63bd14 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/AbstractMarkupAdapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/AbstractMarkupAdapter.java
@@ -24,7 +24,12 @@
import edu.umd.cs.findbugs.annotations.NonNull;
-public abstract class AbstractMarkupAdapter>
+/**
+ * Provides base support for the Metaschema markup
+ * data types.
+ */
+abstract class AbstractMarkupAdapter>
extends AbstractCustomJavaDataTypeAdapter {
/**
@@ -47,7 +52,6 @@ public boolean isXmlMixed() {
return true;
}
- // TODO: verify that read/write methods cannot be generalized in the base class
@Override
public void writeXmlValue(
Object value,
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/AbstractMarkupString.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/AbstractMarkupString.java
index 473629e4b..c529aae06 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/AbstractMarkupString.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/AbstractMarkupString.java
@@ -14,15 +14,15 @@
import com.vladsch.flexmark.util.ast.Node;
import com.vladsch.flexmark.util.ast.TextCollectingVisitor;
-import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.AstCollectingVisitor;
import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.FlexmarkFactory;
-import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.IMarkupVisitor;
-import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.IMarkupWriter;
import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.InsertAnchorExtension;
import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.InsertAnchorExtension.InsertAnchorNode;
-import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.MarkupVisitor;
-import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.MarkupXmlEventWriter;
-import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.MarkupXmlStreamWriter;
+import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl.AstCollectingVisitor;
+import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl.IMarkupVisitor;
+import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl.IMarkupWriter;
+import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl.MarkupVisitor;
+import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl.MarkupXmlEventWriter;
+import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl.MarkupXmlStreamWriter;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
import org.apache.logging.log4j.LogManager;
@@ -52,6 +52,12 @@
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
+/**
+ * The common base for all markup implementations.
+ *
+ * @param
+ * the Java type of the concrete markup implementation
+ */
@SuppressWarnings("PMD.CouplingBetweenObjects")
public abstract class AbstractMarkupString>
implements IMarkupString {
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/IMarkupString.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/IMarkupString.java
index a7e961c99..8e9a06479 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/IMarkupString.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/IMarkupString.java
@@ -26,6 +26,12 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * The common interface for all markup implementations.
+ *
+ * @param
+ * the Java type of the concrete markup implementation
+ */
public interface IMarkupString>
extends ICustomJavaDataType {
/**
@@ -51,22 +57,6 @@ public interface IMarkupString>
*/
boolean isEmpty();
- // /**
- // * Write HTML content to the provided {@code xmlStreamWriter} using the
- // provided {@code
- // namespace}.
- // *
- // * @param writer
- // * the writer
- // * @param namespace
- // * the XML namespace for the HTML
- // * @throws XMLStreamException
- // * if an error occurred while writing
- // */
- // void writeHtml(@NonNull XMLStreamWriter2 writer, @NonNull String namespace)
- // throws
- // XMLStreamException;
-
/**
* Get the HyperText Markup Language (HTML) representation of this markup
* string.
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/MarkupDataTypeProvider.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/MarkupDataTypeProvider.java
index e2836d3ba..8750f4086 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/MarkupDataTypeProvider.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/MarkupDataTypeProvider.java
@@ -15,8 +15,18 @@
*/
public final class MarkupDataTypeProvider
extends AbstractDataTypeProvider {
+ /**
+ * The Metaschema markup-line
+ * data type instance.
+ */
@NonNull
public static final MarkupLineAdapter MARKUP_LINE = new MarkupLineAdapter();
+ /**
+ * The Metaschema markup-multiline
+ * data type instance.
+ */
@NonNull
public static final MarkupMultilineAdapter MARKUP_MULTILINE = new MarkupMultilineAdapter();
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/MarkupLine.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/MarkupLine.java
index 605e95371..ee8ebaa79 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/MarkupLine.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/MarkupLine.java
@@ -14,9 +14,9 @@
import com.vladsch.flexmark.util.data.MutableDataSet;
import com.vladsch.flexmark.util.misc.Extension;
-import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.FlexmarkConfiguration;
import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.FlexmarkFactory;
-import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.SuppressPTagExtension;
+import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl.FlexmarkConfiguration;
+import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl.SuppressPTagExtension;
import java.util.Collection;
import java.util.LinkedList;
@@ -24,6 +24,11 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * Supports a data value which is a single line of markup.
+ *
+ * This markup can be presented as XHTML or Markdown.
+ */
public final class MarkupLine
extends AbstractMarkupString {
@@ -43,7 +48,7 @@ private static DataSet newParserOptions() {
options.set(Parser.LIST_BLOCK_PARSER, false);
options.set(HtmlRenderer.SUPPRESS_HTML_BLOCKS, true);
- Collection currentExtensions = Parser.EXTENSIONS.get(FlexmarkConfiguration.FLEXMARK_CONFIG);
+ Collection currentExtensions = Parser.EXTENSIONS.get(FlexmarkConfiguration.instance());
List extensions = new LinkedList<>(currentExtensions);
extensions.add(SuppressPTagExtension.newInstance());
Parser.EXTENSIONS.set(options, extensions);
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/MarkupLineAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/MarkupLineAdapter.java
index 595668519..6bf2c2452 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/MarkupLineAdapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/MarkupLineAdapter.java
@@ -7,7 +7,6 @@
import com.fasterxml.jackson.core.JsonParser;
-import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.XmlMarkupParser;
import gov.nist.secauto.metaschema.core.metapath.MetapathConstants;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IMarkupItem;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/MarkupMultiline.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/MarkupMultiline.java
index f84205316..08bf7afa8 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/MarkupMultiline.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/MarkupMultiline.java
@@ -11,6 +11,11 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * Supports a data value which may be multiple lines of markup.
+ *
+ * This markup can be presented as XHTML or Markdown.
+ */
public class MarkupMultiline
extends AbstractMarkupString {
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/MarkupMultilineAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/MarkupMultilineAdapter.java
index 560f0e1dc..08850f89b 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/MarkupMultilineAdapter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/MarkupMultilineAdapter.java
@@ -7,7 +7,6 @@
import com.fasterxml.jackson.core.JsonParser;
-import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.XmlMarkupParser;
import gov.nist.secauto.metaschema.core.metapath.MetapathConstants;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IMarkupItem;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/XmlMarkupParser.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/XmlMarkupParser.java
similarity index 97%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/XmlMarkupParser.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/XmlMarkupParser.java
index 6289f6a63..b11747b8e 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/XmlMarkupParser.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/XmlMarkupParser.java
@@ -3,12 +3,10 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.datatype.markup.flexmark;
+package gov.nist.secauto.metaschema.core.datatype.markup;
import com.vladsch.flexmark.util.sequence.Escaping;
-import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine;
-import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline;
import gov.nist.secauto.metaschema.core.model.util.XmlEventUtil;
import gov.nist.secauto.metaschema.core.util.CollectionUtil;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/FlexmarkFactory.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/FlexmarkFactory.java
index 3d8a44947..1570187b8 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/FlexmarkFactory.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/FlexmarkFactory.java
@@ -12,6 +12,9 @@
import com.vladsch.flexmark.parser.Parser;
import com.vladsch.flexmark.util.data.DataHolder;
+import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl.FixedEmphasisDelimiterProcessor;
+import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl.FlexmarkConfiguration;
+
import edu.umd.cs.findbugs.annotations.NonNull;
/**
@@ -58,7 +61,7 @@ public static FlexmarkFactory newInstance(@NonNull DataHolder config) {
}
private FlexmarkFactory() {
- this(FlexmarkConfiguration.FLEXMARK_CONFIG);
+ this(FlexmarkConfiguration.instance());
}
@SuppressWarnings("null")
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/HtmlQuoteTagExtension.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/HtmlQuoteTagExtension.java
index bba9165b8..8c464fbee 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/HtmlQuoteTagExtension.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/HtmlQuoteTagExtension.java
@@ -36,6 +36,10 @@
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
+/**
+ * Adds support for the use of "q" tags in HTML to replace quotation marks.
+ * These are translated to double quotes in Markdown.
+ */
public class HtmlQuoteTagExtension
implements Parser.ParserExtension, HtmlRenderer.HtmlRendererExtension,
FlexmarkHtmlConverter.HtmlConverterExtension {
@@ -77,8 +81,8 @@ public void extend(FlexmarkHtmlConverter.Builder builder) {
static class QTagNodeRenderer implements NodeRenderer {
@Override
- public @Nullable
- Set> getNodeRenderingHandlers() {
+ @Nullable
+ public Set> getNodeRenderingHandlers() {
return Collections.singleton(
new NodeRenderingHandler<>(DoubleQuoteNode.class, this::render));
}
@@ -139,7 +143,9 @@ public Set> getHtmlNodeRendererHandlers() {
return Collections.singleton(new HtmlNodeRendererHandler<>("q", Element.class, this::renderMarkdown));
}
- protected void renderMarkdown(Element element, HtmlNodeConverterContext context,
+ protected void renderMarkdown(
+ Element element,
+ HtmlNodeConverterContext context,
@SuppressWarnings("unused") HtmlMarkdownWriter out) {
context.wrapTextNodes(element, "\"", element.nextElementSibling() != null);
}
@@ -154,7 +160,10 @@ public HtmlNodeRenderer apply(DataHolder options) {
}
- public static class DoubleQuoteNode
+ /**
+ * A Flexmark node implementation representing a quotation mark.
+ */
+ public static final class DoubleQuoteNode
extends TypographicQuotes {
/**
@@ -163,7 +172,6 @@ public static class DoubleQuoteNode
* @param node
* the typographic information pertaining to a double quote
*/
- @SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
public DoubleQuoteNode(TypographicQuotes node) {
super(node.getOpeningMarker(), node.getText(), node.getClosingMarker());
setTypographicOpening(node.getTypographicOpening());
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/InsertAnchorExtension.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/InsertAnchorExtension.java
index cf12d9c35..bf0afd03e 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/InsertAnchorExtension.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/InsertAnchorExtension.java
@@ -50,12 +50,16 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * Extension that adds support for insert anchors, used in OSCAL statements, and
+ * applicable more generally in other Metaschema-based models.
+ */
public class InsertAnchorExtension
implements Parser.ParserExtension, HtmlRenderer.HtmlRendererExtension,
Formatter.FormatterExtension, FlexmarkHtmlConverter.HtmlConverterExtension {
- public static final DataKey ENABLE_INLINE_INSERT_ANCHORS
+ private static final DataKey ENABLE_INLINE_INSERT_ANCHORS
= new DataKey<>("ENABLE_INLINE_INSERT_ANCHORS", true);
- public static final DataKey ENABLE_RENDERING = new DataKey<>("ENABLE_RENDERING", true);
+ private static final DataKey ENABLE_RENDERING = new DataKey<>("ENABLE_RENDERING", true);
/**
* Construct a new extension instance.
@@ -276,6 +280,9 @@ public HtmlNodeRenderer apply(DataHolder options) {
}
}
+ /**
+ * The flexmark node for an insert anchor.
+ */
public static class InsertAnchorNode
extends Node {
@@ -343,9 +350,7 @@ public void setIdReference(@NonNull BasedSequence idReference) {
@Override
@NonNull
public BasedSequence[] getSegments() {
- @NonNull
- BasedSequence[] retval = { getType(), getIdReference() };
- return retval;
+ return new BasedSequence[] { getType(), getIdReference() };
}
@Override
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/AbstractMarkupWriter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/AbstractMarkupWriter.java
index 76a8a950e..6b1867198 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/AbstractMarkupWriter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/AbstractMarkupWriter.java
@@ -43,7 +43,6 @@
import com.vladsch.flexmark.util.sequence.Escaping;
import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.HtmlQuoteTagExtension.DoubleQuoteNode;
-import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.IMarkupWriter;
import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.InsertAnchorExtension.InsertAnchorNode;
import gov.nist.secauto.metaschema.core.util.CollectionUtil;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/AstCollectingVisitor.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/AstCollectingVisitor.java
similarity index 87%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/AstCollectingVisitor.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/AstCollectingVisitor.java
index c97b017b2..451c2e8db 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/AstCollectingVisitor.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/AstCollectingVisitor.java
@@ -3,7 +3,7 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.datatype.markup.flexmark;
+package gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl;
import com.vladsch.flexmark.util.ast.Node;
import com.vladsch.flexmark.util.ast.NodeVisitorBase;
@@ -12,9 +12,13 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * This class supports building a text-based representation of a Markup node
+ * tree.
+ */
public final class AstCollectingVisitor
extends NodeVisitorBase {
- public static final String EOL = "\n";
+ private static final String LINE_SEPARATOR = System.lineSeparator();
@SuppressWarnings("PMD.AvoidStringBufferField") // short lived
private final StringBuilder strBuilder;
@@ -55,7 +59,7 @@ protected void visit(Node node) {
assert node != null;
appendIndent();
node.astString(strBuilder, true);
- strBuilder.append(EOL);
+ strBuilder.append(LINE_SEPARATOR);
indent++;
try {
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/FixedEmphasisDelimiterProcessor.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/FixedEmphasisDelimiterProcessor.java
similarity index 95%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/FixedEmphasisDelimiterProcessor.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/FixedEmphasisDelimiterProcessor.java
index 946d697cc..096edb6b7 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/FixedEmphasisDelimiterProcessor.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/FixedEmphasisDelimiterProcessor.java
@@ -3,7 +3,7 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.datatype.markup.flexmark;
+package gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl;
import com.vladsch.flexmark.ast.Emphasis;
import com.vladsch.flexmark.ast.StrongEmphasis;
@@ -17,7 +17,9 @@
/**
* Provides a temporary fix for the broken {@link EmphasisDelimiterProcessor} in
- * Flexmark.
+ * Flexmark. See the
+ * GitHub pull
+ * request .
*/
public class FixedEmphasisDelimiterProcessor
extends AsteriskDelimiterProcessor {
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/FlexmarkConfiguration.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/FlexmarkConfiguration.java
similarity index 87%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/FlexmarkConfiguration.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/FlexmarkConfiguration.java
index 52013359d..bbfa1ed24 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/FlexmarkConfiguration.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/FlexmarkConfiguration.java
@@ -3,7 +3,7 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.datatype.markup.flexmark;
+package gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl;
import com.vladsch.flexmark.ext.escaped.character.EscapedCharacterExtension;
import com.vladsch.flexmark.ext.gfm.strikethrough.SubscriptExtension;
@@ -21,20 +21,43 @@
import com.vladsch.flexmark.util.format.options.ListBulletMarker;
import com.vladsch.flexmark.util.misc.Extension;
+import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.HtmlQuoteTagExtension;
+import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.InsertAnchorExtension;
+import gov.nist.secauto.metaschema.core.util.ObjectUtils;
+
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
+import nl.talsmasoftware.lazy4j.Lazy;
+/**
+ * This class manages a shared Flexmark configuration for use by other
+ * implementations.
+ */
public final class FlexmarkConfiguration {
@NonNull
private static final ParserEmulationProfile PARSER_PROFILE = ParserEmulationProfile.COMMONMARK_0_29;
+ /**
+ * The shared Flexmark configuration.
+ */
@NonNull
- public static final DataSet FLEXMARK_CONFIG = initFlexmarkConfig();
+ private static final Lazy FLEXMARK_CONFIG
+ = ObjectUtils.notNull(Lazy.lazy(FlexmarkConfiguration::initFlexmarkConfig));
+
+ /**
+ * Get the singleton configuration instance.
+ *
+ * @return the configuration
+ */
+ @NonNull
+ public static DataSet instance() {
+ return ObjectUtils.notNull(FLEXMARK_CONFIG.get());
+ }
@SuppressWarnings("null")
@NonNull
@@ -133,7 +156,7 @@ private static DataSet initFlexmarkConfig() {
* @return the configuration
*/
public static DataSet newFlexmarkConfig(@Nullable DataHolder options) {
- return options == null ? FLEXMARK_CONFIG : DataSet.merge(FLEXMARK_CONFIG, options);
+ return options == null ? instance() : DataSet.merge(instance(), options);
}
private FlexmarkConfiguration() {
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/HtmlCodeRenderExtension.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/HtmlCodeRenderExtension.java
similarity index 89%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/HtmlCodeRenderExtension.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/HtmlCodeRenderExtension.java
index ae356bc38..f098e96df 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/HtmlCodeRenderExtension.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/HtmlCodeRenderExtension.java
@@ -3,7 +3,7 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.datatype.markup.flexmark;
+package gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl;
import com.vladsch.flexmark.ast.Code;
import com.vladsch.flexmark.ast.Text;
@@ -32,6 +32,12 @@
import edu.umd.cs.findbugs.annotations.Nullable;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+/**
+ * A Flexmark HTML renderer extension that customizes the rendering of code
+ * blocks within Metaschema documents. This implementation provides special
+ * handling for source position tracking and custom HTML tags while maintaining
+ * standard Markdown code block semantics.
+ */
public class HtmlCodeRenderExtension
implements HtmlRenderer.HtmlRendererExtension {
private static final Pattern EOL_PATTERN = Pattern.compile("\r\n|\r|\n");
@@ -79,12 +85,10 @@ private void render( // NOPMD actually used in lambda
boolean customTag = htmlOptions.codeStyleHtmlOpen != null || htmlOptions.codeStyleHtmlClose != null;
if (customTag) {
html.raw(ObjectUtils.notNull(htmlOptions.codeStyleHtmlOpen));
+ } else if (context.getHtmlOptions().sourcePositionParagraphLines) {
+ html.withAttr().tag("code");
} else {
- if (context.getHtmlOptions().sourcePositionParagraphLines) {
- html.withAttr().tag("code");
- } else {
- html.srcPos(node.getText()).withAttr().tag("code");
- }
+ html.srcPos(node.getText()).withAttr().tag("code");
}
if (codeSoftLineBreaks && !htmlOptions.isSoftBreakAllSpaces) {
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/IMarkupVisitor.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/IMarkupVisitor.java
similarity index 76%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/IMarkupVisitor.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/IMarkupVisitor.java
index e20741280..68fd00585 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/IMarkupVisitor.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/IMarkupVisitor.java
@@ -3,13 +3,22 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.datatype.markup.flexmark;
+package gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl;
import com.vladsch.flexmark.util.ast.Document;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+/**
+ * Support for visiting a Flexmark syntax tree.
+ *
+ * @param
+ * the Java type of sync to write to
+ * @param
+ * the Java type of exception that can be thrown when a writing error
+ * occurs
+ */
@SuppressFBWarnings("THROWS_METHOD_THROWS_CLAUSE_THROWABLE")
public interface IMarkupVisitor {
/**
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/IMarkupWriter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/IMarkupWriter.java
similarity index 97%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/IMarkupWriter.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/IMarkupWriter.java
index df01dc58f..377927487 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/IMarkupWriter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/IMarkupWriter.java
@@ -3,7 +3,7 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.datatype.markup.flexmark;
+package gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl;
import com.vladsch.flexmark.ast.AutoLink;
import com.vladsch.flexmark.ast.BlockQuote;
@@ -40,6 +40,15 @@
import edu.umd.cs.findbugs.annotations.Nullable;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+/**
+ * A common interface for writing markup to some form of an output sync.
+ *
+ * @param
+ * the Java type of sync to write to
+ * @param
+ * the Java type of exception that can be thrown when a writing error
+ * occurs
+ */
@SuppressFBWarnings(value = "THROWS_METHOD_THROWS_CLAUSE_THROWABLE",
justification = "There is a need to support varying exceptions from multiple stream writers")
public interface IMarkupWriter { // NOPMD
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/MarkupVisitor.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/MarkupVisitor.java
similarity index 99%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/MarkupVisitor.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/MarkupVisitor.java
index 5cd0891a3..c16759cea 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/MarkupVisitor.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/MarkupVisitor.java
@@ -3,7 +3,7 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.datatype.markup.flexmark;
+package gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl;
import com.vladsch.flexmark.ast.AutoLink;
import com.vladsch.flexmark.ast.BlockQuote;
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/MarkupXmlEventWriter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/MarkupXmlEventWriter.java
similarity index 97%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/MarkupXmlEventWriter.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/MarkupXmlEventWriter.java
index 006a30a4f..94336e025 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/MarkupXmlEventWriter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/MarkupXmlEventWriter.java
@@ -3,11 +3,10 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.datatype.markup.flexmark;
+package gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl;
import com.vladsch.flexmark.parser.ListOptions;
-import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl.AbstractMarkupWriter;
import gov.nist.secauto.metaschema.core.util.CollectionUtil;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
@@ -27,6 +26,9 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * Provides support for writing Flexmark markup nodes to an XML event stream.
+ */
public class MarkupXmlEventWriter
extends AbstractMarkupWriter {
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/MarkupXmlStreamWriter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/MarkupXmlStreamWriter.java
similarity index 79%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/MarkupXmlStreamWriter.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/MarkupXmlStreamWriter.java
index 86831d0bd..752c04caf 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/MarkupXmlStreamWriter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/MarkupXmlStreamWriter.java
@@ -3,12 +3,10 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.datatype.markup.flexmark;
+package gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl;
import com.vladsch.flexmark.parser.ListOptions;
-import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl.AbstractMarkupWriter;
-
import java.util.Map;
import javax.xml.namespace.QName;
@@ -17,7 +15,24 @@
import edu.umd.cs.findbugs.annotations.NonNull;
-// TODO: Is this orphaned code needed?
+/**
+ * Provides support for writing Flexmark markup nodes to an XML stream. This
+ * implementation uses {@link XMLStreamWriter} to write markup elements and
+ * their attributes in a streaming fashion.
+ *
+ * This class is not thread-safe and should not be shared between threads
+ * without external synchronization.
+ *
+ * Example usage:
+ *
+ *
{@code
+ * XMLStreamWriter writer = ...;
+ * MarkupXmlStreamWriter markupWriter = new MarkupXmlStreamWriter(
+ * "http://example.com/ns",
+ * ListOptions.getDefaultListOptions(),
+ * writer);
+ * }
+ */
public class MarkupXmlStreamWriter
extends AbstractMarkupWriter {
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/SuppressPTagExtension.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/SuppressPTagExtension.java
similarity index 94%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/SuppressPTagExtension.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/SuppressPTagExtension.java
index 683c75720..4e146c379 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/SuppressPTagExtension.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/SuppressPTagExtension.java
@@ -3,7 +3,7 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.datatype.markup.flexmark;
+package gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl;
import com.vladsch.flexmark.ast.Paragraph;
import com.vladsch.flexmark.html.HtmlRenderer;
@@ -21,6 +21,10 @@
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
+/**
+ * Provides the ability to suppress paragraph "p" tags for single line markup
+ * generation.
+ */
public class SuppressPTagExtension
implements HtmlRenderer.HtmlRendererExtension {
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/object/AbstractAmbiguousTemporal.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/object/AbstractAmbiguousTemporal.java
index 303ad3600..4f89018ff 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/object/AbstractAmbiguousTemporal.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/object/AbstractAmbiguousTemporal.java
@@ -12,6 +12,9 @@
import edu.umd.cs.findbugs.annotations.NonNull;
/**
+ * Implementations of this class represent a temporal value which may not have a
+ * timezone making it ambiguous as a point/window in time.
+ *
* Metaschema has a need to represent dates and times that allow for an
* ambiguous time zone. This is due to some models not requiring a time zone as
* part of a date/time. An ambiguous dateTime allows a time zone to be inferred,
@@ -22,7 +25,9 @@
* written back out in such cases.
*
* @param
- * the bound object type
+ * the bound object type that extends this class, used for proper type
+ * inheritance in implementing classes like {@code AmbiguousDate} or
+ * {@code AmbiguousDateTime}
*/
public abstract class AbstractAmbiguousTemporal>
extends AbstractCustomJavaDataType {
@@ -52,4 +57,10 @@ public AbstractAmbiguousTemporal(@NonNull ZonedDateTime value, boolean hasTimeZo
public boolean hasTimeZone() {
return timeZone;
}
+
+ @Override
+ public String toString() {
+ return getValue().toString() + (hasTimeZone() ? "" : "(abiguous)");
+ }
+
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/object/AmbiguousDate.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/object/AmbiguousDate.java
new file mode 100644
index 000000000..d00ef1522
--- /dev/null
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/object/AmbiguousDate.java
@@ -0,0 +1,58 @@
+/*
+ * SPDX-FileCopyrightText: none
+ * SPDX-License-Identifier: CC0-1.0
+ */
+
+package gov.nist.secauto.metaschema.core.datatype.object;
+
+import java.time.ZonedDateTime;
+import java.util.Objects;
+
+import edu.umd.cs.findbugs.annotations.NonNull;
+
+/**
+ * Represents a date value which may not have a timezone making it ambiguous as
+ * a window in time.
+ */
+public class AmbiguousDate
+ extends AbstractAmbiguousTemporal {
+
+ /**
+ * Construct a new date object. This type supports ambiguous dates that were
+ * provided without a time zone.
+ *
+ * The date value will be ambiguous if the {@code hasTimeZone} is {@code false}.
+ *
+ * @param value
+ * the date value
+ * @param hasTimeZone
+ * {@code true} if the date is intended to have an associated time zone
+ * or {@code false} otherwise
+ */
+ public AmbiguousDate(@NonNull ZonedDateTime value, boolean hasTimeZone) {
+ super(value, hasTimeZone);
+ }
+
+ @Override
+ public AmbiguousDate copy() {
+ return new AmbiguousDate(getValue(), hasTimeZone());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getValue(), hasTimeZone());
+ }
+
+ @SuppressWarnings("PMD.OnlyOneReturn")
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof AmbiguousDate)) {
+ return false;
+ }
+ AmbiguousDate other = (AmbiguousDate) obj;
+ return hasTimeZone() == other.hasTimeZone() && getValue().equals(other.getValue());
+ }
+}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/object/AmbiguousDateTime.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/object/AmbiguousDateTime.java
new file mode 100644
index 000000000..99dfd9ac6
--- /dev/null
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/object/AmbiguousDateTime.java
@@ -0,0 +1,59 @@
+/*
+ * SPDX-FileCopyrightText: none
+ * SPDX-License-Identifier: CC0-1.0
+ */
+
+package gov.nist.secauto.metaschema.core.datatype.object;
+
+import java.time.ZonedDateTime;
+import java.util.Objects;
+
+import edu.umd.cs.findbugs.annotations.NonNull;
+
+/**
+ * Represents a date/time value which may not have a timezone making it
+ * ambiguous as a point in time.
+ */
+public class AmbiguousDateTime
+ extends AbstractAmbiguousTemporal {
+
+ /**
+ * Construct a new date/time object. This type supports ambiguous dates/times
+ * that were provided without a time zone.
+ *
+ * The date/time value will be ambiguous if the {@code hasTimeZone} is
+ * {@code false}.
+ *
+ * @param value
+ * the date/time value
+ * @param hasTimeZone
+ * {@code true} if the date/time is intended to have an associated time
+ * zone or {@code false} otherwise
+ */
+ public AmbiguousDateTime(@NonNull ZonedDateTime value, boolean hasTimeZone) {
+ super(value, hasTimeZone);
+ }
+
+ @Override
+ public AmbiguousDateTime copy() {
+ return new AmbiguousDateTime(getValue(), hasTimeZone());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getValue(), hasTimeZone());
+ }
+
+ @SuppressWarnings("PMD.OnlyOneReturn")
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof AmbiguousDateTime)) {
+ return false;
+ }
+ AmbiguousDateTime other = (AmbiguousDateTime) obj;
+ return hasTimeZone() == other.hasTimeZone() && getValue().equals(other.getValue());
+ }
+}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/object/Date.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/object/Date.java
deleted file mode 100644
index 6a26460ef..000000000
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/object/Date.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SPDX-FileCopyrightText: none
- * SPDX-License-Identifier: CC0-1.0
- */
-
-package gov.nist.secauto.metaschema.core.datatype.object;
-
-import java.time.ZonedDateTime;
-
-import edu.umd.cs.findbugs.annotations.NonNull;
-
-public class Date // NOPMD - intentional
- extends AbstractAmbiguousTemporal {
-
- /**
- * Construct a new date object. This type supports ambiguous dates that were
- * provided without a time zone.
- *
- * @param value
- * the date value
- * @param hasTimeZone
- * {@code true} if the date is intended to have an associated time zone
- * or {@code false} otherwise
- */
- public Date(@NonNull ZonedDateTime value, boolean hasTimeZone) {
- super(value, hasTimeZone);
- }
-
- @Override
- public Date copy() {
- return new Date(getValue(), hasTimeZone());
- }
-}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/object/DateTime.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/object/DateTime.java
deleted file mode 100644
index 197f7ecce..000000000
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/object/DateTime.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SPDX-FileCopyrightText: none
- * SPDX-License-Identifier: CC0-1.0
- */
-
-package gov.nist.secauto.metaschema.core.datatype.object;
-
-import java.time.ZonedDateTime;
-
-import edu.umd.cs.findbugs.annotations.NonNull;
-
-public class DateTime
- extends AbstractAmbiguousTemporal {
-
- /**
- * Construct a new date/time object. This type supports ambiguous dates/times
- * that were provided without a time zone.
- *
- * @param value
- * the date/time value
- * @param hasTimeZone
- * {@code true} if the date/time is intended to have an associated time
- * zone or {@code false} otherwise
- */
- public DateTime(@NonNull ZonedDateTime value, boolean hasTimeZone) {
- super(value, hasTimeZone);
- }
-
- @Override
- public DateTime copy() {
- return new DateTime(getValue(), hasTimeZone());
- }
-}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/EQNameUtils.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/EQNameUtils.java
index e62fb0a00..82b173318 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/EQNameUtils.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/EQNameUtils.java
@@ -13,6 +13,9 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * Utilities for managing qualified names.
+ */
public final class EQNameUtils {
private static final Pattern URI_QUALIFIED_NAME = Pattern.compile("^Q\\{([^{}]*)\\}(.+)$");
private static final Pattern LEXICAL_NAME = Pattern.compile("^(?:([^:]+):)?(.+)$");
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/ICollectionValue.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/ICollectionValue.java
index 834276250..6f6b5dfd6 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/ICollectionValue.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/ICollectionValue.java
@@ -12,6 +12,9 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * A data value that can be a value in a Metapath array or map.
+ */
public interface ICollectionValue {
/**
* Get the collection value as a sequence.
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/IPrintable.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/IPrintable.java
index 7ff7c7b87..cb63888fc 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/IPrintable.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/IPrintable.java
@@ -7,6 +7,10 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * Identifies the implementation as being able to produce a string value for
+ * output.
+ */
public interface IPrintable {
/**
* Get the string value.
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/MetapathConstants.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/MetapathConstants.java
index 6dc3652d9..d389ec1e6 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/MetapathConstants.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/MetapathConstants.java
@@ -9,48 +9,98 @@
import java.net.URI;
-import javax.xml.XMLConstants;
-
import edu.umd.cs.findbugs.annotations.NonNull;
/**
- * Provides constant values used in Metapath.
+ * Provides constant values for use in Metapath.
*/
@SuppressWarnings("PMD.DataClass")
public final class MetapathConstants {
+ /**
+ * The namespace URI for Metapath data types and built-in casting functions.
+ */
@NonNull
public static final URI NS_METAPATH = ObjectUtils.requireNonNull(
URI.create("http://csrc.nist.gov/ns/metaschema/metapath"));
- @NonNull
- public static final URI NS_XML_SCHEMA = ObjectUtils.requireNonNull(
- URI.create(XMLConstants.W3C_XML_SCHEMA_NS_URI));
+ /**
+ * The namespace URI for Metapath built-in functions.
+ *
+ * @see #PREFIX_METAPATH for the default prefix for this namespace
+ */
@NonNull
public static final URI NS_METAPATH_FUNCTIONS = ObjectUtils.requireNonNull(
URI.create("http://csrc.nist.gov/ns/metaschema/metapath-functions"));
+ /**
+ * The namespace URI for Metapath math-related built-in functions.
+ *
+ * @see #PREFIX_METAPATH_FUNCTIONS_MATH for the default prefix for this
+ * namespace
+ */
@NonNull
public static final URI NS_METAPATH_FUNCTIONS_MATH = ObjectUtils.requireNonNull(
URI.create(NS_METAPATH_FUNCTIONS + "/math"));
+ /**
+ * The namespace URI for Metapath array-related built-in functions.
+ *
+ * @see #PREFIX_METAPATH_FUNCTIONS_ARRAY for the default prefix for this
+ * namespace
+ */
@NonNull
public static final URI NS_METAPATH_FUNCTIONS_ARRAY = ObjectUtils.requireNonNull(
URI.create(NS_METAPATH_FUNCTIONS + "/array"));
+ /**
+ * The namespace URI for Metapath map-related built-in functions.
+ *
+ * @see #PREFIX_METAPATH_FUNCTIONS_MAP for the default prefix for this namespace
+ */
@NonNull
public static final URI NS_METAPATH_FUNCTIONS_MAP = ObjectUtils.requireNonNull(
URI.create(NS_METAPATH_FUNCTIONS + "/map"));
+ /**
+ * The namespace URI for Metapath extension built-in functions.
+ *
+ * This is currently an alias for {@link #NS_METAPATH_FUNCTIONS} and can be used
+ * when implementing custom extension functions to distinguish them from core
+ * functions.
+ */
@NonNull
public static final URI NS_METAPATH_FUNCTIONS_EXTENDED = NS_METAPATH_FUNCTIONS;
+ /**
+ * The namespace prefix for Metapath data types and built-in casting functions.
+ *
+ * @see #NS_METAPATH for the corresponding namespace URI
+ */
@NonNull
public static final String PREFIX_METAPATH = "meta";
+ /**
+ * The namespace prefix for Metapath built-in functions.
+ *
+ * @see #NS_METAPATH_FUNCTIONS for the corresponding namespace URI
+ */
@NonNull
- public static final String PREFIX_XML_SCHEMA = "xs";
- @NonNull
- public static final String PREFIX_XPATH_FUNCTIONS = "mp";
+ public static final String PREFIX_METAPATH_FUNCTIONS = "mp";
+ /**
+ * The namespace prefix for Metapath math-related built-in functions.
+ *
+ * @see #NS_METAPATH_FUNCTIONS_MATH for the corresponding namespace URI
+ */
@NonNull
- public static final String PREFIX_XPATH_FUNCTIONS_MATH = "math";
+ public static final String PREFIX_METAPATH_FUNCTIONS_MATH = "math";
+ /**
+ * The namespace prefix for Metapath array-related built-in functions.
+ *
+ * @see #NS_METAPATH_FUNCTIONS_ARRAY for the corresponding namespace URI
+ */
@NonNull
- public static final String PREFIX_XPATH_FUNCTIONS_ARRAY = "array";
+ public static final String PREFIX_METAPATH_FUNCTIONS_ARRAY = "array";
+ /**
+ * The namespace prefix for Metapath map-related built-in functions.
+ *
+ * @see #NS_METAPATH_FUNCTIONS_MAP for the corresponding namespace URI
+ */
@NonNull
- public static final String PREFIX_XPATH_FUNCTIONS_MAP = "map";
+ public static final String PREFIX_METAPATH_FUNCTIONS_MAP = "map";
private MetapathConstants() {
// disable construction
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/MetapathExpression.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/MetapathExpression.java
index 2cdcfdaed..a7f931347 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/MetapathExpression.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/MetapathExpression.java
@@ -18,7 +18,6 @@
import gov.nist.secauto.metaschema.core.metapath.function.library.FnData;
import gov.nist.secauto.metaschema.core.metapath.item.IItem;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem;
-import gov.nist.secauto.metaschema.core.metapath.item.atomic.IDecimalItem;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.INumericItem;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
@@ -48,34 +47,90 @@
})
public class MetapathExpression {
+ /**
+ * Identifies the expected type for a Metapath evaluation result.
+ */
public enum ResultType {
/**
* The result is expected to be a {@link BigDecimal} value.
*/
- NUMBER,
+ NUMBER(BigDecimal.class, sequence -> {
+ INumericItem numeric = FunctionUtils.toNumeric(sequence, true);
+ return numeric == null ? null : numeric.asDecimal();
+ }),
/**
* The result is expected to be a {@link String} value.
*/
- STRING,
+ STRING(String.class, sequence -> {
+ IAnyAtomicItem item = FnData.fnData(sequence).getFirstItem(true);
+ return item == null ? "" : item.asString();
+ }),
/**
* The result is expected to be a {@link Boolean} value.
*/
- BOOLEAN,
+ BOOLEAN(Boolean.class, sequence -> FnBoolean.fnBoolean(sequence).toBoolean()),
/**
* The result is expected to be an {@link ISequence} value.
*/
- SEQUENCE,
+ SEQUENCE(ISequence.class, sequence -> sequence),
/**
* The result is expected to be an {@link IItem} value.
*/
- ITEM;
- }
+ ITEM(IItem.class, sequence -> sequence.getFirstItem(true));
- private static final Logger LOGGER = LogManager.getLogger(MetapathExpression.class);
+ @NonNull
+ private final Class> clazz;
+ private final ConversionFunction converter;
+
+ ResultType(@NonNull Class> clazz, @NonNull ConversionFunction converter) {
+ this.clazz = clazz;
+ this.converter = converter;
+ }
+
+ /**
+ * Get the expected class for the result type.
+ *
+ * @return the expected class
+ *
+ */
+ @NonNull
+ public Class> expectedClass() {
+ return clazz;
+ }
+ /**
+ * Convert the provided sequence to the expected type.
+ *
+ * @param
+ * the Java type of the expected return value
+ * @param sequence
+ * the Metapath result sequence to convert
+ * @return the converted sequence as the expected type
+ * @throws TypeMetapathException
+ * if the provided sequence is incompatible with the expected result
+ * type
+ */
+ @Nullable
+ public T convert(@NonNull ISequence> sequence) {
+ try {
+ return ObjectUtils.asNullableType(converter.convert(sequence));
+ } catch (ClassCastException ex) {
+ throw new InvalidTypeMetapathException(null,
+ String.format("Unable to cast to expected result type '%s' using expected type '%s'.",
+ name(),
+ expectedClass().getName()),
+ ex);
+ }
+ }
+ }
+
+ /**
+ * The Metapath expression identifying the current context node.
+ */
@NonNull
public static final MetapathExpression CONTEXT_NODE
= new MetapathExpression(".", ContextItem.instance(), StaticContext.instance());
+ private static final Logger LOGGER = LogManager.getLogger(MetapathExpression.class);
@NonNull
private final String path;
@@ -231,7 +286,7 @@ public String toString() {
* type
* @throws MetapathException
* if an error occurred during evaluation
- * @see #toResultType(ISequence, ResultType)
+ * @see ResultType#convert(ISequence)
*/
@Nullable
public T evaluateAs(@NonNull ResultType resultType) {
@@ -255,14 +310,14 @@ public T evaluateAs(@NonNull ResultType resultType) {
* type
* @throws MetapathException
* if an error occurred during evaluation
- * @see #toResultType(ISequence, ResultType)
+ * @see ResultType#convert(ISequence)
*/
@Nullable
public T evaluateAs(
@Nullable IItem focus,
@NonNull ResultType resultType) {
ISequence> result = evaluate(focus);
- return toResultType(result, resultType);
+ return resultType.convert(result);
}
/**
@@ -286,7 +341,7 @@ public T evaluateAs(
* type
* @throws MetapathException
* if an error occurred during evaluation
- * @see #toResultType(ISequence, ResultType)
+ * @see ResultType#convert(ISequence)
*/
@Nullable
public T evaluateAs(
@@ -294,62 +349,7 @@ public T evaluateAs(
@NonNull ResultType resultType,
@NonNull DynamicContext dynamicContext) {
ISequence> result = evaluate(focus, dynamicContext);
- return toResultType(result, resultType);
- }
-
- /**
- * Converts the provided {@code sequence} to the requested {@code resultType}.
- *
- * The {@code resultType} determines the returned result, which is derived from
- * the evaluation result sequence, as follows:
- *
- * BOOLEAN - the effective boolean result is produced using
- * {@link FnBoolean#fnBoolean(ISequence)}.
- * NODE - the first result item in the sequence is returned.
- * NUMBER - the sequence is cast to a number using
- * {@link IDecimalItem#cast(IAnyAtomicItem)}.
- * SEQUENCE - the evaluation result sequence.
- * STRING - the string value of the first result item in the sequence.
- *
- *
- * @param
- * the requested return value
- * @param sequence
- * the sequence to convert
- * @param resultType
- * the type of result to produce
- * @return the converted result
- * @throws TypeMetapathException
- * if the provided sequence is incompatible with the requested result
- * type
- */
- @SuppressWarnings({ "PMD.NullAssignment", "PMD.CyclomaticComplexity" }) // for readability
- @Nullable
- protected T toResultType(@NonNull ISequence> sequence, @NonNull ResultType resultType) {
- Object result;
- switch (resultType) {
- case BOOLEAN:
- result = FnBoolean.fnBoolean(sequence).toBoolean();
- break;
- case ITEM:
- result = sequence.getFirstItem(true);
- break;
- case NUMBER:
- INumericItem numeric = FunctionUtils.toNumeric(sequence, true);
- result = numeric == null ? null : numeric.asDecimal();
- break;
- case SEQUENCE:
- result = sequence;
- break;
- case STRING:
- IAnyAtomicItem item = FnData.fnData(sequence).getFirstItem(true);
- result = item == null ? "" : item.asString();
- break;
- default:
- throw new InvalidTypeMetapathException(null, String.format("unsupported result type '%s'", resultType.name()));
- }
-
- return ObjectUtils.asNullableType(result);
+ return resultType.convert(result);
}
/**
@@ -419,4 +419,10 @@ public ISequence evaluate(
ex);
}
}
+
+ @FunctionalInterface
+ interface ConversionFunction {
+ @Nullable
+ Object convert(@NonNull ISequence> sequence);
+ }
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/StaticContext.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/StaticContext.java
index 13bce12ee..626db41a1 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/StaticContext.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/StaticContext.java
@@ -37,19 +37,16 @@ public final class StaticContext {
MetapathConstants.PREFIX_METAPATH,
MetapathConstants.NS_METAPATH);
knownNamespaces.put(
- MetapathConstants.PREFIX_XML_SCHEMA,
- MetapathConstants.NS_XML_SCHEMA);
- knownNamespaces.put(
- MetapathConstants.PREFIX_XPATH_FUNCTIONS,
+ MetapathConstants.PREFIX_METAPATH_FUNCTIONS,
MetapathConstants.NS_METAPATH_FUNCTIONS);
knownNamespaces.put(
- MetapathConstants.PREFIX_XPATH_FUNCTIONS_MATH,
+ MetapathConstants.PREFIX_METAPATH_FUNCTIONS_MATH,
MetapathConstants.NS_METAPATH_FUNCTIONS_MATH);
knownNamespaces.put(
- MetapathConstants.PREFIX_XPATH_FUNCTIONS_ARRAY,
+ MetapathConstants.PREFIX_METAPATH_FUNCTIONS_ARRAY,
MetapathConstants.NS_METAPATH_FUNCTIONS_ARRAY);
knownNamespaces.put(
- MetapathConstants.PREFIX_XPATH_FUNCTIONS_MAP,
+ MetapathConstants.PREFIX_METAPATH_FUNCTIONS_MAP,
MetapathConstants.NS_METAPATH_FUNCTIONS_MAP);
WELL_KNOWN_NAMESPACES = CollectionUtil.unmodifiableMap(knownNamespaces);
@@ -362,7 +359,7 @@ public static Builder builder() {
* A builder used to generate the static context.
*/
public static final class Builder {
- public boolean useWildcardWhenNamespaceNotDefaulted; // false
+ private boolean useWildcardWhenNamespaceNotDefaulted; // false
@Nullable
private URI baseUri;
@NonNull
@@ -373,18 +370,7 @@ public static final class Builder {
private URI defaultFunctionNamespace = MetapathConstants.NS_METAPATH_FUNCTIONS;
private Builder() {
- namespaces.put(
- MetapathConstants.PREFIX_METAPATH,
- MetapathConstants.NS_METAPATH);
- namespaces.put(
- MetapathConstants.PREFIX_XML_SCHEMA,
- MetapathConstants.NS_XML_SCHEMA);
- namespaces.put(
- MetapathConstants.PREFIX_XPATH_FUNCTIONS,
- MetapathConstants.NS_METAPATH_FUNCTIONS);
- namespaces.put(
- MetapathConstants.PREFIX_XPATH_FUNCTIONS_MATH,
- MetapathConstants.NS_METAPATH_FUNCTIONS_MATH);
+ // avoid direct construction
}
/**
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/antlr/AbstractAstVisitor.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/antlr/AbstractAstVisitor.java
index 1b682f269..50c59be96 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/antlr/AbstractAstVisitor.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/antlr/AbstractAstVisitor.java
@@ -79,8 +79,19 @@
import edu.umd.cs.findbugs.annotations.NonNull;
-public abstract class AbstractAstVisitor // NOPMD
+/**
+ * This abstract class supports processing an ANTLR-based abstract syntax tree
+ * by walking the tree using a visitor pattern.
+ *
+ * @param
+ * the Java type of the result produced through visitation
+ */
+@SuppressWarnings({ "PMD.ExcessivePublicCount", "PMD.CyclomaticComplexity" })
+public abstract class AbstractAstVisitor
extends Metapath10BaseVisitor {
+ private static final String ERR_NO_DELEGATION
+ = "This method should never be called directly as it is handled by the parent expression.";
+ private static final String ERR_SINGLE_CHILD = "A single child expression was expected.";
/**
* This dispatch method will call the node handler on a leaf node or if multiple
@@ -125,7 +136,7 @@ protected R delegateToChild(@NonNull T ctx) {
if (ctx.getChildCount() == 1) {
return ctx.getChild(0).accept(this);
}
- throw new IllegalStateException("a single child expression was expected");
+ throw new IllegalStateException(ERR_SINGLE_CHILD);
}
// ============================================================
@@ -150,7 +161,7 @@ public R visitMetapath(MetapathContext ctx) {
@Override
public R visitExpr(ExprContext ctx) {
assert ctx != null;
- return handle(ctx, (context) -> handleExpr(ctx));
+ return handle(ctx, this::handleExpr);
}
@Override
@@ -185,7 +196,7 @@ public R visitPrimaryexpr(PrimaryexprContext ctx) {
@Override
public R visitLiteral(LiteralContext ctx) {
assert ctx != null;
- return handle(ctx, (context) -> handleStringLiteral(ctx));
+ return handle(ctx, this::handleStringLiteral);
}
/**
@@ -200,7 +211,7 @@ public R visitLiteral(LiteralContext ctx) {
@Override
public R visitNumericliteral(NumericliteralContext ctx) {
assert ctx != null;
- return handle(ctx, (context) -> handleNumericLiteral(ctx));
+ return handle(ctx, this::handleNumericLiteral);
}
// ==================================================================
@@ -266,7 +277,7 @@ public R visitParenthesizedexpr(ParenthesizedexprContext ctx) {
@Override
public R visitContextitemexpr(ContextitemexprContext ctx) {
assert ctx != null;
- return handle(ctx, (context) -> handleContextitemexpr(ctx));
+ return handle(ctx, this::handleContextitemexpr);
}
// =========================================================================
@@ -285,19 +296,19 @@ public R visitContextitemexpr(ContextitemexprContext ctx) {
@Override
public R visitFunctioncall(FunctioncallContext ctx) {
assert ctx != null;
- return handle(ctx, (context) -> handleFunctioncall(ctx));
+ return handle(ctx, this::handleFunctioncall);
}
@Override
public R visitArgumentlist(ArgumentlistContext ctx) {
// should never be called, since this is handled by the parent expression
- throw new IllegalStateException();
+ throw new IllegalStateException(ERR_NO_DELEGATION);
}
@Override
public R visitArgument(ArgumentContext ctx) {
// should never be called, since this is handled by the parent expression
- throw new IllegalStateException();
+ throw new IllegalStateException(ERR_NO_DELEGATION);
}
// =======================================================================
@@ -326,7 +337,7 @@ public R visitEnclosedexpr(EnclosedexprContext ctx) {
@Override
public R visitPostfixexpr(PostfixexprContext ctx) {
assert ctx != null;
- return handle(ctx, (context) -> handlePostfixexpr(ctx));
+ return handle(ctx, this::handlePostfixexpr);
}
/**
@@ -375,7 +386,7 @@ public R visitLookup(LookupContext ctx) {
@Override
public R visitPathexpr(PathexprContext ctx) {
assert ctx != null;
- return handle(ctx, (context) -> handlePathexpr(ctx));
+ return handle(ctx, this::handlePathexpr);
}
// ============================================================
@@ -395,7 +406,7 @@ public R visitPathexpr(PathexprContext ctx) {
@Override
public R visitRelativepathexpr(RelativepathexprContext ctx) {
assert ctx != null;
- return handle(ctx, (context) -> handleRelativepathexpr(ctx));
+ return handle(ctx, this::handleRelativepathexpr);
}
// ================================================
@@ -421,7 +432,7 @@ public R visitStepexpr(StepexprContext ctx) {
public R visitForwardstep(ForwardstepContext ctx) {
assert ctx != null;
// this will either call the handler or forward for AbbrevforwardstepContext
- return handle(ctx, (context) -> handleForwardstep(ctx));
+ return handle(ctx, this::handleForwardstep);
}
/**
@@ -437,7 +448,7 @@ public R visitForwardstep(ForwardstepContext ctx) {
public R visitReversestep(ReversestepContext ctx) {
assert ctx != null;
// this will either call the handler or forward for AbbrevreversestepContext
- return handle(ctx, (context) -> handleReversestep(ctx));
+ return handle(ctx, this::handleReversestep);
}
// ======================================================================
@@ -456,13 +467,13 @@ public R visitReversestep(ReversestepContext ctx) {
@Override
public R visitAxisstep(AxisstepContext ctx) {
assert ctx != null;
- return handle(ctx, (context) -> handleAxisstep(ctx));
+ return handle(ctx, this::handleAxisstep);
}
@Override
public R visitPredicatelist(PredicatelistContext ctx) {
// should never be called, since this is handled by the parent expression
- throw new IllegalStateException();
+ throw new IllegalStateException(ERR_NO_DELEGATION);
}
// ===========================================
@@ -472,13 +483,13 @@ public R visitPredicatelist(PredicatelistContext ctx) {
@Override
public R visitForwardaxis(ForwardaxisContext ctx) {
// should never be called, since this is handled by handleForwardstep
- throw new IllegalStateException();
+ throw new IllegalStateException(ERR_NO_DELEGATION);
}
@Override
public R visitReverseaxis(ReverseaxisContext ctx) {
// should never be called, since this is handled by handleReversestep
- throw new IllegalStateException();
+ throw new IllegalStateException(ERR_NO_DELEGATION);
}
// =======================================================
@@ -488,19 +499,19 @@ public R visitReverseaxis(ReverseaxisContext ctx) {
@Override
public R visitNodetest(NodetestContext ctx) {
// should never be called, since this is handled by the calling context
- throw new IllegalStateException();
+ throw new IllegalStateException(ERR_NO_DELEGATION);
}
@Override
public R visitNametest(NametestContext ctx) {
// should never be called, since this is handled by the calling context
- throw new IllegalStateException();
+ throw new IllegalStateException(ERR_NO_DELEGATION);
}
@Override
public R visitEqname(EqnameContext ctx) {
// should never be called, since this is handled by the calling context
- throw new IllegalStateException();
+ throw new IllegalStateException(ERR_NO_DELEGATION);
}
/**
@@ -569,7 +580,7 @@ public R visitAbbrevreversestep(AbbrevreversestepContext ctx) {
@Override
public R visitRangeexpr(RangeexprContext ctx) {
assert ctx != null;
- return handle(ctx, (context) -> handleRangeexpr(ctx));
+ return handle(ctx, this::handleRangeexpr);
}
// ========================================================================
@@ -588,7 +599,7 @@ public R visitRangeexpr(RangeexprContext ctx) {
@Override
public R visitUnionexpr(UnionexprContext ctx) {
assert ctx != null;
- return handle(ctx, (context) -> handleUnionexpr(ctx));
+ return handle(ctx, this::handleUnionexpr);
}
/**
@@ -603,7 +614,7 @@ public R visitUnionexpr(UnionexprContext ctx) {
@Override
public R visitIntersectexceptexpr(IntersectexceptexprContext ctx) {
assert ctx != null;
- return handle(ctx, (context) -> handleIntersectexceptexpr(ctx));
+ return handle(ctx, this::handleIntersectexceptexpr);
}
// ======================================================================
@@ -622,7 +633,7 @@ public R visitIntersectexceptexpr(IntersectexceptexprContext ctx) {
@Override
public R visitAdditiveexpr(AdditiveexprContext ctx) {
assert ctx != null;
- return handle(ctx, (context) -> handleAdditiveexpr(ctx));
+ return handle(ctx, this::handleAdditiveexpr);
}
/**
@@ -637,7 +648,7 @@ public R visitAdditiveexpr(AdditiveexprContext ctx) {
@Override
public R visitMultiplicativeexpr(MultiplicativeexprContext ctx) {
assert ctx != null;
- return handle(ctx, (context) -> handleMultiplicativeexpr(ctx));
+ return handle(ctx, this::handleMultiplicativeexpr);
}
/**
@@ -652,7 +663,7 @@ public R visitMultiplicativeexpr(MultiplicativeexprContext ctx) {
@Override
public R visitUnaryexpr(UnaryexprContext ctx) {
assert ctx != null;
- return handle(ctx, (context) -> handleUnaryexpr(ctx));
+ return handle(ctx, this::handleUnaryexpr);
}
@Override
@@ -678,7 +689,7 @@ public R visitValueexpr(ValueexprContext ctx) {
@Override
public R visitStringconcatexpr(StringconcatexprContext ctx) {
assert ctx != null;
- return handle(ctx, (context) -> handleStringconcatexpr(ctx));
+ return handle(ctx, this::handleStringconcatexpr);
}
// =======================================================================
@@ -697,19 +708,19 @@ public R visitStringconcatexpr(StringconcatexprContext ctx) {
@Override
public R visitComparisonexpr(ComparisonexprContext ctx) {
assert ctx != null;
- return handle(ctx, (context) -> handleComparisonexpr(ctx));
+ return handle(ctx, this::handleComparisonexpr);
}
@Override
public R visitValuecomp(ValuecompContext ctx) {
// should never be called, since this is handled by the parent expression
- throw new IllegalStateException();
+ throw new IllegalStateException(ERR_NO_DELEGATION);
}
@Override
public R visitGeneralcomp(GeneralcompContext ctx) {
// should never be called, since this is handled by the parent expression
- throw new IllegalStateException();
+ throw new IllegalStateException(ERR_NO_DELEGATION);
}
// ============================================================================
@@ -728,7 +739,7 @@ public R visitGeneralcomp(GeneralcompContext ctx) {
@Override
public R visitOrexpr(OrexprContext ctx) {
assert ctx != null;
- return handle(ctx, (context) -> handleOrexpr(ctx));
+ return handle(ctx, this::handleOrexpr);
}
/**
@@ -743,7 +754,7 @@ public R visitOrexpr(OrexprContext ctx) {
@Override
public R visitAndexpr(AndexprContext ctx) {
assert ctx != null;
- return handle(ctx, (context) -> handleAndexpr(ctx));
+ return handle(ctx, this::handleAndexpr);
}
// ====================================================================
@@ -762,19 +773,19 @@ public R visitAndexpr(AndexprContext ctx) {
@Override
public R visitForexpr(ForexprContext ctx) {
assert ctx != null;
- return handle(ctx, (context) -> handleForexpr(ctx));
+ return handle(ctx, this::handleForexpr);
}
@Override
public R visitSimpleforclause(SimpleforclauseContext ctx) {
// should never be called, since this is handled by the parent expression
- throw new IllegalStateException();
+ throw new IllegalStateException(ERR_NO_DELEGATION);
}
@Override
public R visitSimpleforbinding(SimpleforbindingContext ctx) {
// should never be called, since this is handled by the parent expression
- throw new IllegalStateException();
+ throw new IllegalStateException(ERR_NO_DELEGATION);
}
// ====================================================================
@@ -799,13 +810,13 @@ public R visitLetexpr(LetexprContext ctx) {
@Override
public R visitSimpleletclause(SimpleletclauseContext ctx) {
// should never be called, since this is handled by the parent expression
- throw new IllegalStateException();
+ throw new IllegalStateException(ERR_NO_DELEGATION);
}
@Override
public R visitSimpleletbinding(SimpleletbindingContext ctx) {
// should never be called, since this is handled by the parent expression
- throw new IllegalStateException();
+ throw new IllegalStateException(ERR_NO_DELEGATION);
}
// ======================================================================
@@ -830,7 +841,7 @@ public R visitMapconstructor(MapconstructorContext ctx) {
@Override
public R visitMapconstructorentry(MapconstructorentryContext ctx) {
// should never be called, since this is handled by the parent expression
- throw new IllegalStateException();
+ throw new IllegalStateException(ERR_NO_DELEGATION);
}
@Override
@@ -888,7 +899,7 @@ public R visitCurlyarrayconstructor(CurlyarrayconstructorContext ctx) {
@Override
public R visitKeyspecifier(KeyspecifierContext ctx) {
// should never be called, since this is handled by the parent expression
- throw new IllegalStateException();
+ throw new IllegalStateException(ERR_NO_DELEGATION);
}
/**
@@ -922,7 +933,7 @@ public R visitUnarylookup(UnarylookupContext ctx) {
@Override
public R visitIfexpr(IfexprContext ctx) {
assert ctx != null;
- return handle(ctx, (context) -> handleIfexpr(ctx));
+ return handle(ctx, this::handleIfexpr);
}
/*
@@ -966,7 +977,7 @@ public R visitQuantifiedexpr(QuantifiedexprContext ctx) {
@Override
public R visitSimplemapexpr(SimplemapexprContext ctx) {
assert ctx != null;
- return handle(ctx, (context) -> handleSimplemapexpr(ctx));
+ return handle(ctx, this::handleSimplemapexpr);
}
/*
@@ -987,12 +998,12 @@ public R visitSimplemapexpr(SimplemapexprContext ctx) {
@Override
public R visitArrowexpr(ArrowexprContext ctx) {
assert ctx != null;
- return handle(ctx, (context) -> handleArrowexpr(ctx));
+ return handle(ctx, this::handleArrowexpr);
}
@Override
public R visitArrowfunctionspecifier(ArrowfunctionspecifierContext ctx) {
// should never be called, since this is handled by the parent expression
- throw new IllegalStateException();
+ throw new IllegalStateException(ERR_NO_DELEGATION);
}
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/antlr/FailingErrorListener.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/antlr/FailingErrorListener.java
index aea605851..94dcb57c4 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/antlr/FailingErrorListener.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/antlr/FailingErrorListener.java
@@ -10,6 +10,13 @@
import org.antlr.v4.runtime.Recognizer;
import org.antlr.v4.runtime.misc.ParseCancellationException;
+/**
+ * An ANTLR error listener that throws a {@link ParseCancellationException} when
+ * a syntax error is found.
+ *
+ * The exception message contains details around the line and character position
+ * where the error occurred.
+ */
public class FailingErrorListener
extends BaseErrorListener {
@Override
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/antlr/Metapath10ParserBase.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/antlr/Metapath10ParserBase.java
index 44f8661d6..8931064ef 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/antlr/Metapath10ParserBase.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/antlr/Metapath10ParserBase.java
@@ -8,8 +8,40 @@
import org.antlr.v4.runtime.Parser;
import org.antlr.v4.runtime.TokenStream;
+import java.util.Set;
+
+/**
+ * Base class for Metapath ANTLR-based parsing operations. This class extends
+ * the ANTLR Parser to provide specialized processing for Metapath expressions.
+ *
+ * ANTLR (ANother Tool for Language Recognition) is used here to generate the
+ * parser for Metapath expressions. This base class provides common
+ * functionality that can be used by the generated parser implementation.
+ *
+ * Implementations should extend this class to define specific parsing rules and
+ * behaviors for Metapath processing.
+ */
public abstract class Metapath10ParserBase
extends Parser {
+
+ private static final Set KEYWORD_TOKENS = Set.of(
+ Metapath10.KW_ARRAY,
+ Metapath10.KW_FLAG,
+ Metapath10.KW_COMMENT,
+ Metapath10.KW_DOCUMENT_NODE,
+ Metapath10.KW_ELEMENT,
+ Metapath10.KW_EMPTY_SEQUENCE,
+ Metapath10.KW_FUNCTION,
+ Metapath10.KW_IF,
+ Metapath10.KW_ITEM,
+ Metapath10.KW_MAP,
+ Metapath10.KW_NAMESPACE_NODE,
+ Metapath10.KW_NODE,
+ Metapath10.KW_PROCESSING_INSTRUCTION,
+ Metapath10.KW_SCHEMA_ATTRIBUTE,
+ Metapath10.KW_SCHEMA_ELEMENT,
+ Metapath10.KW_TEXT);
+
/**
* Construct a new parser base.
*
@@ -27,21 +59,7 @@ protected Metapath10ParserBase(TokenStream input) {
* {@code false} otherwise
*/
protected boolean isFuncCall() {
- return !(getInputStream().LA(1) == Metapath10.KW_ARRAY
- || getInputStream().LA(1) == Metapath10.KW_FLAG
- || getInputStream().LA(1) == Metapath10.KW_COMMENT
- || getInputStream().LA(1) == Metapath10.KW_DOCUMENT_NODE
- || getInputStream().LA(1) == Metapath10.KW_ELEMENT
- || getInputStream().LA(1) == Metapath10.KW_EMPTY_SEQUENCE
- || getInputStream().LA(1) == Metapath10.KW_FUNCTION
- || getInputStream().LA(1) == Metapath10.KW_IF
- || getInputStream().LA(1) == Metapath10.KW_ITEM
- || getInputStream().LA(1) == Metapath10.KW_MAP
- || getInputStream().LA(1) == Metapath10.KW_NAMESPACE_NODE
- || getInputStream().LA(1) == Metapath10.KW_NODE
- || getInputStream().LA(1) == Metapath10.KW_PROCESSING_INSTRUCTION
- || getInputStream().LA(1) == Metapath10.KW_SCHEMA_ATTRIBUTE
- || getInputStream().LA(1) == Metapath10.KW_SCHEMA_ELEMENT
- || getInputStream().LA(1) == Metapath10.KW_TEXT);
+ int nextToken = getInputStream().LA(1);
+ return !KEYWORD_TOKENS.contains(nextToken);
}
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/antlr/ParseTreePrinter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/antlr/ParseTreePrinter.java
index b70e28cec..1cf327c21 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/antlr/ParseTreePrinter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/antlr/ParseTreePrinter.java
@@ -14,6 +14,10 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * Supports walking an ANTLR parse tree to generate a textual representation of
+ * the tree.
+ */
public class ParseTreePrinter {
@SuppressWarnings("resource")
@NotOwning
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/ComparisonFunctions.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/ComparisonFunctions.java
index aab9f3737..4d53bb5cc 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/ComparisonFunctions.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/ComparisonFunctions.java
@@ -147,10 +147,10 @@ private static IAnyAtomicItem applyGeneralComparisonCast(@NonNull IAnyAtomicItem
retval = IDecimalItem.cast(other);
} else if (item instanceof IDayTimeDurationItem) {
retval = IDayTimeDurationItem.cast(other);
- } else if (item instanceof IDayTimeDurationItem) {
+ } else if (item instanceof IYearMonthDurationItem) {
retval = IYearMonthDurationItem.cast(other);
} else {
- retval = item.getJavaTypeAdapter().cast(other);
+ retval = item.castAsType(other);
}
return retval;
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/FunctionUtils.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/FunctionUtils.java
index a968762bb..b7cb48fa6 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/FunctionUtils.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/FunctionUtils.java
@@ -127,6 +127,9 @@ public static INumericItem toNumeric(@NonNull ISequence> sequence, boolean req
public static INumericItem toNumeric(@NonNull IItem item) {
// atomize
IAnyAtomicItem atomicItem = ISequence.getFirstItem(FnData.atomize(item), true);
+ if (atomicItem == null) {
+ throw new InvalidTypeMetapathException(item, "Unable to cast null item");
+ }
return toNumeric(atomicItem);
}
@@ -140,7 +143,7 @@ public static INumericItem toNumeric(@NonNull IItem item) {
* if the item cannot be cast to a numeric value
*/
@NonNull
- public static INumericItem toNumeric(@Nullable IAnyAtomicItem item) {
+ public static INumericItem toNumeric(@NonNull IAnyAtomicItem item) {
try {
return IDecimalItem.cast(item);
} catch (InvalidValueForCastFunctionException ex) {
@@ -237,7 +240,8 @@ public static TYPE requireType(Class clazz, IItem ite
null,
String.format("Expected non-null type '%s', but the node was null.",
clazz.getName()));
- } else if (!clazz.isInstance(item)) {
+ }
+ if (!clazz.isInstance(item)) {
throw new InvalidTypeMetapathException(
item,
String.format("Expected type '%s', but the node was type '%s'.",
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/CastFunction.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/CastFunction.java
index 8d75eee9c..3ee86412b 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/CastFunction.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/CastFunction.java
@@ -36,12 +36,12 @@ public final class CastFunction- implements IFunctio
static
- IFunction signature(
@NonNull URI namespace,
@NonNull String name,
- @NonNull Class
- resulingAtomicType,
+ @NonNull Class
- resultingAtomicType,
@NonNull ICastExecutor
- executor) {
return signature(
ObjectUtils.notNull(namespace.toASCIIString()),
name,
- resulingAtomicType,
+ resultingAtomicType,
executor);
}
@@ -96,6 +96,12 @@ public ISequence
- execute(@NonNull IFunction function,
return ISequence.of(castItem);
}
+ /**
+ * A callback used to perform a casting operation.
+ *
+ * @param
-
+ * the Java type for the resulting item
+ */
@FunctionalInterface
public interface ICastExecutor
- {
/**
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/DefaultFunctionLibrary.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/DefaultFunctionLibrary.java
index c4eab2db9..d5b984abf 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/DefaultFunctionLibrary.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/DefaultFunctionLibrary.java
@@ -34,6 +34,7 @@ public class DefaultFunctionLibrary
/**
* Initialize the built-in function library.
*/
+ @SuppressWarnings("deprecation")
public DefaultFunctionLibrary() { // NOPMD - intentional
// https://www.w3.org/TR/xpath-functions-31/#func-abs
registerFunction(FnAbs.SIGNATURE);
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnCeiling.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnCeiling.java
index 407634a19..99626871e 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnCeiling.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnCeiling.java
@@ -20,8 +20,8 @@
import edu.umd.cs.findbugs.annotations.NonNull;
/**
- * Implements the XPath 3.1
- *
fn:round
+ * Implements the XPath 3.1 fn:ceiling
* function.
*/
public final class FnCeiling {
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnMinMax.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnMinMax.java
index 45bd024b3..afca2be5d 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnMinMax.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnMinMax.java
@@ -15,13 +15,19 @@
import gov.nist.secauto.metaschema.core.metapath.item.IItem;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyUriItem;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IBase64BinaryItem;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IBooleanItem;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IDateItem;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IDateTimeItem;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IDecimalItem;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IDurationItem;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IStringItem;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IUntypedAtomicItem;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -37,7 +43,21 @@
public final class FnMinMax {
private static final String NAME_MIN = "min";
private static final String NAME_MAX = "max";
-
+ /**
+ * Defines the set of primitive atomic item types supported by the min/max
+ * functions. This set is used for type validation and normalization during
+ * comparison operations.
+ */
+ @NonNull
+ private static final Set> PRIMITIVE_ITEM_TYPES = ObjectUtils.notNull(Set.of(
+ IStringItem.class,
+ IBooleanItem.class,
+ IDecimalItem.class,
+ IDurationItem.class,
+ IDateTimeItem.class,
+ IDateItem.class,
+ IBase64BinaryItem.class,
+ IAnyUriItem.class));
@NonNull
static final IFunction SIGNATURE_MIN = IFunction.builder()
.name(NAME_MIN)
@@ -149,36 +169,57 @@ private static Stream extends IAnyAtomicItem> normalize(
return Stream.of(items.get(0));
}
- List extends IAnyAtomicItem> resultingItems = ObjectUtils.notNull(items.stream()
+ List extends IAnyAtomicItem> resultingItems = convertUntypedItems(items);
+ Map, Integer> counts = countItemTypes(resultingItems);
+ return createNormalizedStream(resultingItems, counts);
+ }
+
+ @NonNull
+ private static List extends IAnyAtomicItem> convertUntypedItems(
+ @NonNull List extends IAnyAtomicItem> items) {
+ return ObjectUtils.notNull(items.stream()
.map(item -> item instanceof IUntypedAtomicItem ? IDecimalItem.cast(item) : item)
.collect(Collectors.toList()));
+ }
- Map, Integer> counts = FunctionUtils.countTypes(
- IAnyAtomicItem.PRIMITIVE_ITEM_TYPES,
- resultingItems);
+ @NonNull
+ private static Map, Integer> countItemTypes(
+ @NonNull List extends IAnyAtomicItem> items) {
+ return FunctionUtils.countTypes(PRIMITIVE_ITEM_TYPES, items);
+ }
- Stream extends IAnyAtomicItem> stream = null;
+ @SuppressWarnings("PMD.OnlyOneReturn")
+ @NonNull
+ private static Stream extends IAnyAtomicItem> createNormalizedStream(
+ @NonNull List extends IAnyAtomicItem> items,
+ @NonNull Map, Integer> counts) {
+
+ // Single type - no conversion needed
if (counts.size() == 1) {
- stream = resultingItems.stream();
- } else if (counts.size() > 1) {
- int size = resultingItems.size();
+ return ObjectUtils.notNull(items.stream());
+ }
+
+ // Multiple types - attempt conversion
+ int size = items.size();
+ if (counts.size() > 1) {
+ // Check if all items are either String or AnyUri
if (counts.getOrDefault(IStringItem.class, 0) + counts.getOrDefault(IAnyUriItem.class, 0) == size) {
- stream = resultingItems.stream()
- .map(IAnyAtomicItem::asStringItem);
- } else if (counts.getOrDefault(IDecimalItem.class, 0) == size) {
- stream = resultingItems.stream()
- .map(item -> (IDecimalItem) item);
+ return ObjectUtils.notNull(items.stream().map(IAnyAtomicItem::asStringItem));
}
- }
- if (stream == null) {
- throw new InvalidArgumentFunctionException(
- InvalidArgumentFunctionException.INVALID_ARGUMENT_TYPE,
- String.format("Values must all be of a single atomic type. Their types are '%s'.",
- FunctionUtils.getTypes(resultingItems).stream()
- .map(Class::getName)
- .collect(Collectors.joining(","))));
+ // Check if all items are Decimal
+ if (counts.getOrDefault(IDecimalItem.class, 0) == size) {
+ return ObjectUtils.notNull(items.stream().map(item -> (IDecimalItem) item));
+ }
}
- return stream;
+
+ // No valid conversion possible
+ throw new InvalidArgumentFunctionException(
+ InvalidArgumentFunctionException.INVALID_ARGUMENT_TYPE,
+ String.format(
+ "Values must all be of a single atomic type. Found multiple types: [%s]",
+ FunctionUtils.getTypes(items).stream()
+ .map(Class::getSimpleName)
+ .collect(Collectors.joining(", "))));
}
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapEntry.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapEntry.java
index 6d0c41d9b..9500d8bb2 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapEntry.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapEntry.java
@@ -29,7 +29,7 @@
public final class MapEntry {
private static final String NAME = "entry";
@NonNull
- public static final IFunction SIGNATURE = IFunction.builder()
+ static final IFunction SIGNATURE = IFunction.builder()
.name(NAME)
.namespace(MetapathConstants.NS_METAPATH_FUNCTIONS_MAP)
.deterministic()
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractAnyAtomicItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractAnyAtomicItem.java
index 334e0c92c..c12c9d4d2 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractAnyAtomicItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractAnyAtomicItem.java
@@ -5,18 +5,19 @@
package gov.nist.secauto.metaschema.core.metapath.item.atomic;
-import gov.nist.secauto.metaschema.core.datatype.IDataTypeAdapter;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
import edu.umd.cs.findbugs.annotations.NonNull;
/**
- * Provides a common implementation for all atomic types.
+ * Provides a common implementation for all atomic types that have an underlying
+ * value.
*
* @param
* the Java type associated with the atomic type.
*/
-public abstract class AbstractAnyAtomicItem implements IAnyAtomicItem {
+public abstract class AbstractAnyAtomicItem
+ extends AbstractAtomicItemBase {
@NonNull
private final TYPE value;
@@ -36,17 +37,4 @@ public TYPE getValue() {
return value;
}
- @Override
- @NonNull
- public abstract IDataTypeAdapter getJavaTypeAdapter();
-
- @Override
- public String asString() {
- return getJavaTypeAdapter().asString(getValue());
- }
-
- @Override
- public String toString() {
- return asString();
- }
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractAtomicItemBase.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractAtomicItemBase.java
new file mode 100644
index 000000000..c3c3c6a92
--- /dev/null
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractAtomicItemBase.java
@@ -0,0 +1,33 @@
+/*
+ * SPDX-FileCopyrightText: none
+ * SPDX-License-Identifier: CC0-1.0
+ */
+
+package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+
+import gov.nist.secauto.metaschema.core.datatype.IDataTypeAdapter;
+
+import edu.umd.cs.findbugs.annotations.NonNull;
+
+/**
+ * Provides base functionality for atomic item implementations.
+ *
+ * @param
+ * the Java type of the underlying data value
+ */
+public abstract class AbstractAtomicItemBase implements IAnyAtomicItem {
+
+ @Override
+ @NonNull
+ public abstract IDataTypeAdapter getJavaTypeAdapter();
+
+ @Override
+ public String asString() {
+ return getJavaTypeAdapter().asString(getValue());
+ }
+
+ @Override
+ public String toString() {
+ return asString();
+ }
+}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/DateTimeWithoutTimeZoneItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/DateTimeWithoutTimeZoneItemImpl.java
deleted file mode 100644
index 182a7bcdf..000000000
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/DateTimeWithoutTimeZoneItemImpl.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * SPDX-FileCopyrightText: none
- * SPDX-License-Identifier: CC0-1.0
- */
-
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
-
-import gov.nist.secauto.metaschema.core.datatype.adapter.DateTimeAdapter;
-import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
-import gov.nist.secauto.metaschema.core.datatype.object.DateTime;
-
-import java.time.ZonedDateTime;
-
-import edu.umd.cs.findbugs.annotations.NonNull;
-
-class DateTimeWithoutTimeZoneItemImpl
- extends AbstractDateTimeItem {
-
- public DateTimeWithoutTimeZoneItemImpl(@NonNull DateTime value) {
- super(value);
- }
-
- @Override
- public ZonedDateTime asZonedDateTime() {
- return getValue().getValue();
- }
-
- @Override
- public DateTimeAdapter getJavaTypeAdapter() {
- return MetaschemaDataTypeProvider.DATE_TIME;
- }
-
-}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/DateWithoutTimeZoneItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/DateWithoutTimeZoneItemImpl.java
deleted file mode 100644
index 806cee2ce..000000000
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/DateWithoutTimeZoneItemImpl.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * SPDX-FileCopyrightText: none
- * SPDX-License-Identifier: CC0-1.0
- */
-
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
-
-import gov.nist.secauto.metaschema.core.datatype.adapter.DateAdapter;
-import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
-import gov.nist.secauto.metaschema.core.datatype.object.Date;
-
-import java.time.ZonedDateTime;
-
-import edu.umd.cs.findbugs.annotations.NonNull;
-
-class DateWithoutTimeZoneItemImpl
- extends AbstractDateItem {
-
- public DateWithoutTimeZoneItemImpl(@NonNull Date value) {
- super(value);
- }
-
- @Override
- public ZonedDateTime asZonedDateTime() {
- return getValue().getValue();
- }
-
- @Override
- public DateAdapter getJavaTypeAdapter() {
- return MetaschemaDataTypeProvider.DATE;
- }
-}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IAnyAtomicItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IAnyAtomicItem.java
index 13f20a671..fef08f6fe 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IAnyAtomicItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IAnyAtomicItem.java
@@ -7,26 +7,19 @@
import gov.nist.secauto.metaschema.core.datatype.IDataTypeAdapter;
import gov.nist.secauto.metaschema.core.metapath.IPrintable;
+import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
import gov.nist.secauto.metaschema.core.metapath.item.IItemVisitor;
import gov.nist.secauto.metaschema.core.metapath.item.function.IMapItem;
import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey;
-import gov.nist.secauto.metaschema.core.util.ObjectUtils;
-
-import java.util.Set;
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * The interface shared by all atomic items, representing indivisible data
+ * values that serve as the fundamental building blocks for complex data
+ * structures in the Metaschema framework.
+ */
public interface IAnyAtomicItem extends IAtomicValuedItem, IPrintable {
- @NonNull
- Set> PRIMITIVE_ITEM_TYPES = ObjectUtils.notNull(Set.of(
- IStringItem.class,
- IBooleanItem.class,
- IDecimalItem.class,
- IDurationItem.class,
- IDateTimeItem.class,
- IDateItem.class,
- IBase64BinaryItem.class,
- IAnyUriItem.class));
@Override
@NonNull
@@ -90,7 +83,9 @@ default IStringItem asStringItem() {
*
* @param item
* the item to cast
- * @return the result from casting
+ * @return an atomic item of this type
+ * @throws InvalidValueForCastFunctionException
+ * if the provided item type cannot be cast to this item type
*/
@NonNull
IAnyAtomicItem castAsType(@NonNull IAnyAtomicItem item);
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IAnyUriItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IAnyUriItem.java
index f9359fede..2521e5bdf 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IAnyUriItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IAnyUriItem.java
@@ -6,13 +6,18 @@
package gov.nist.secauto.metaschema.core.metapath.item.atomic;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
+import gov.nist.secauto.metaschema.core.metapath.InvalidTypeMetapathException;
import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.impl.AnyUriItemImpl;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
import java.net.URI;
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * An atomic Metapath item containing a URI data value.
+ */
public interface IAnyUriItem extends IAnyAtomicItem {
/**
* Construct a new URI item using the provided string {@code value}.
@@ -20,16 +25,32 @@ public interface IAnyUriItem extends IAnyAtomicItem {
* @param value
* a string representing a URI
* @return the new item
- * @throws IllegalArgumentException
+ * @throws InvalidTypeMetapathException
* if the given string violates RFC2396
*/
@NonNull
static IAnyUriItem valueOf(@NonNull String value) {
- return valueOf(ObjectUtils.notNull(URI.create(value)));
+ try {
+ return valueOf(MetaschemaDataTypeProvider.URI.parse(value));
+ } catch (IllegalArgumentException ex) {
+ throw new InvalidTypeMetapathException(
+ null,
+ String.format("Invalid URI value '%s'. %s",
+ value,
+ ex.getLocalizedMessage()),
+ ex);
+ }
}
/**
* Construct a new URI item using the provided URI {@code value}.
+ *
+ * Example usage:
+ *
+ *
+ * URI uri = URI.create("http://example.com");
+ * IAnyUriItem item = IAnyUriItem.valueOf(uri);
+ *
*
* @param value
* a URI
@@ -59,7 +80,19 @@ static IAnyUriItem valueOf(@NonNull URI value) {
*/
@NonNull
static IAnyUriItem cast(@NonNull IAnyAtomicItem item) {
- return MetaschemaDataTypeProvider.URI.cast(item);
+ try {
+ return item instanceof IAnyUriItem
+ ? (IAnyUriItem) item
+ : valueOf(item.asString());
+ } catch (IllegalStateException | InvalidTypeMetapathException ex) {
+ // asString can throw IllegalStateException exception
+ throw new InvalidValueForCastFunctionException(ex);
+ }
+ }
+
+ @Override
+ default IAnyUriItem castAsType(IAnyAtomicItem item) {
+ return cast(item);
}
/**
@@ -102,11 +135,6 @@ default IAnyUriItem resolve(@NonNull IAnyUriItem other) {
return valueOf(ObjectUtils.notNull(asUri().resolve(other.asUri())));
}
- @Override
- default IAnyUriItem castAsType(IAnyAtomicItem item) {
- return cast(item);
- }
-
@Override
default int compareTo(IAnyAtomicItem item) {
return compareTo(cast(item));
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IBase64BinaryItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IBase64BinaryItem.java
index a86039042..82a912079 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IBase64BinaryItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IBase64BinaryItem.java
@@ -6,14 +6,16 @@
package gov.nist.secauto.metaschema.core.metapath.item.atomic;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
+import gov.nist.secauto.metaschema.core.metapath.InvalidTypeMetapathException;
import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.impl.Base64BinaryItemImpl;
import java.nio.ByteBuffer;
import edu.umd.cs.findbugs.annotations.NonNull;
/**
- * A Metapath atomic item containing a Base64 encoded data value.
+ * An atomic Metapath item containing a Base64 encoded data value.
*/
public interface IBase64BinaryItem extends IAnyAtomicItem {
@@ -24,10 +26,21 @@ public interface IBase64BinaryItem extends IAnyAtomicItem {
* @param value
* a string representing base64 encoded data
* @return the new item
+ * @throws InvalidTypeMetapathException
+ * if the provided string is not a valid Base64 character sequence
*/
@NonNull
static IBase64BinaryItem valueOf(@NonNull String value) {
- return cast(IStringItem.valueOf(value));
+ try {
+ return valueOf(MetaschemaDataTypeProvider.BASE64.parse(value));
+ } catch (IllegalArgumentException ex) {
+ throw new InvalidTypeMetapathException(
+ null,
+ String.format("The value starting with '%s' is not a valid Base64 character sequence. %s",
+ value.substring(0, Math.min(value.length(), 200)),
+ ex.getLocalizedMessage()),
+ ex);
+ }
}
/**
@@ -55,7 +68,14 @@ static IBase64BinaryItem valueOf(@NonNull ByteBuffer value) {
*/
@NonNull
static IBase64BinaryItem cast(@NonNull IAnyAtomicItem item) {
- return MetaschemaDataTypeProvider.BASE64.cast(item);
+ try {
+ return item instanceof IBase64BinaryItem
+ ? (IBase64BinaryItem) item
+ : valueOf(item.asString());
+ } catch (IllegalStateException | InvalidTypeMetapathException ex) {
+ // asString can throw IllegalStateException exception
+ throw new InvalidValueForCastFunctionException(ex);
+ }
}
@Override
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IBooleanItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IBooleanItem.java
index 79ad9ee28..20016c0ed 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IBooleanItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IBooleanItem.java
@@ -6,12 +6,14 @@
package gov.nist.secauto.metaschema.core.metapath.item.atomic;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
+import gov.nist.secauto.metaschema.core.metapath.InvalidTypeMetapathException;
import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.impl.BooleanItemImpl;
import edu.umd.cs.findbugs.annotations.NonNull;
/**
- * A Metapath atomic item with a boolean value.
+ * An atomic Metapath item with a boolean value.
*/
public interface IBooleanItem extends IAnyAtomicItem {
/**
@@ -34,6 +36,8 @@ public interface IBooleanItem extends IAnyAtomicItem {
* @param value
* a string representing a boolean value
* @return the new item
+ * @throws InvalidTypeMetapathException
+ * if the provided value is not a valid boolean value
*/
@NonNull
static IBooleanItem valueOf(@NonNull String value) {
@@ -42,10 +46,13 @@ static IBooleanItem valueOf(@NonNull String value) {
retval = TRUE;
} else {
try {
- Boolean bool = MetaschemaDataTypeProvider.BOOLEAN.parse(value);
- retval = valueOf(bool);
+ retval = valueOf(MetaschemaDataTypeProvider.BOOLEAN.parse(value));
} catch (IllegalArgumentException ex) {
- throw new InvalidValueForCastFunctionException(String.format("Unable to parse string value '%s'", value),
+ throw new InvalidTypeMetapathException(
+ null,
+ String.format("Invalid boolean value '%s'. %s",
+ value,
+ ex.getLocalizedMessage()),
ex);
}
}
@@ -76,7 +83,29 @@ static IBooleanItem valueOf(boolean value) {
*/
@NonNull
static IBooleanItem cast(@NonNull IAnyAtomicItem item) {
- return MetaschemaDataTypeProvider.BOOLEAN.cast(item);
+ IBooleanItem retval;
+ if (item instanceof INumericItem) {
+ retval = valueOf(((INumericItem) item).toEffectiveBoolean());
+ } else {
+ try {
+ retval = valueOf(INumericItem.cast(item).toEffectiveBoolean());
+ } catch (InvalidValueForCastFunctionException ex) {
+ try {
+ retval = valueOf(item.asString());
+ } catch (IllegalStateException | InvalidTypeMetapathException ex2) {
+ // asString can throw IllegalStateException exception
+ InvalidValueForCastFunctionException thrown = new InvalidValueForCastFunctionException(ex2);
+ thrown.addSuppressed(ex);
+ throw thrown;
+ }
+ }
+ }
+ return retval;
+ }
+
+ @Override
+ default IBooleanItem castAsType(IAnyAtomicItem item) {
+ return cast(item);
}
/**
@@ -86,11 +115,6 @@ static IBooleanItem cast(@NonNull IAnyAtomicItem item) {
*/
boolean toBoolean();
- @Override
- default IBooleanItem castAsType(IAnyAtomicItem item) {
- return cast(item);
- }
-
/**
* Get the boolean negation of this value.
*
@@ -103,7 +127,7 @@ default IBooleanItem negate() {
@Override
default int compareTo(IAnyAtomicItem item) {
- return compareTo(cast(item));
+ return compareTo(castAsType(item));
}
/**
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDateItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDateItem.java
index 4223748a3..c29e38f66 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDateItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDateItem.java
@@ -6,15 +6,24 @@
package gov.nist.secauto.metaschema.core.metapath.item.atomic;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
-import gov.nist.secauto.metaschema.core.datatype.object.Date;
+import gov.nist.secauto.metaschema.core.datatype.object.AmbiguousDate;
+import gov.nist.secauto.metaschema.core.datatype.object.AmbiguousDateTime;
+import gov.nist.secauto.metaschema.core.metapath.InvalidTypeMetapathException;
import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.impl.DateWithTimeZoneItemImpl;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.impl.DateWithoutTimeZoneItemImpl;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
+import java.time.LocalDate;
+import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * An atomic Metapath item containing a date data value.
+ */
public interface IDateItem extends ITemporalItem {
/**
@@ -29,20 +38,64 @@ static IDateItem valueOf(@NonNull String value) {
try {
return valueOf(MetaschemaDataTypeProvider.DATE.parse(value));
} catch (IllegalArgumentException ex) {
- throw new InvalidValueForCastFunctionException(String.format("Unable to parse string value '%s'", value), ex);
+ throw new InvalidTypeMetapathException(
+ null,
+ String.format("Invalid date value '%s'. %s",
+ value,
+ ex.getLocalizedMessage()),
+ ex);
}
}
/**
* Construct a new date item using the provided {@code value}.
+ *
+ * This method handles recording that the timezone is implicit.
+ *
+ * @param value
+ * a date, without time zone information
+ * @return the new item
+ * @see AmbiguousDateTime for more details on timezone handling
+ */
+ @NonNull
+ static IDateItem valueOf(@NonNull LocalDate value) {
+ return valueOf(ObjectUtils.notNull(value.atStartOfDay(ZoneOffset.UTC)), false);
+ }
+
+ /**
+ * Construct a new date item using the provided {@code value}.
+ *
+ * This method handles recording if an explicit timezone was provided using the
+ * {@code hasTimeZone} parameter. The {@link AmbiguousDate#hasTimeZone()} method
+ * can be called to determine if timezone information is present.
*
* @param value
* a date, without time zone information
+ * @param hasTimeZone
+ * {@code true} if the date/time is intended to have an associated time
+ * zone or {@code false} otherwise
* @return the new item
+ * @see AmbiguousDateTime for more details on timezone handling
*/
@NonNull
- static IDateItem valueOf(@NonNull Date value) {
- return new DateWithoutTimeZoneItemImpl(value);
+ static IDateItem valueOf(@NonNull ZonedDateTime value, boolean hasTimeZone) {
+ return hasTimeZone
+ ? valueOf(value)
+ : valueOf(new AmbiguousDate(value, false));
+ }
+
+ /**
+ * Construct a new date item using the provided {@code value}.
+ *
+ * @param value
+ * an ambiguous date with time zone information already identified
+ * @return the new item
+ */
+ @NonNull
+ static IDateItem valueOf(@NonNull AmbiguousDate value) {
+ return value.hasTimeZone()
+ ? valueOf(value.getValue())
+ : new DateWithoutTimeZoneItemImpl(value);
}
/**
@@ -71,13 +124,28 @@ static IDateItem valueOf(@NonNull ZonedDateTime value) {
*/
@NonNull
static IDateItem cast(@NonNull IAnyAtomicItem item) {
- return MetaschemaDataTypeProvider.DATE.cast(item);
+ IDateItem retval;
+ if (item instanceof IDateItem) {
+ retval = (IDateItem) item;
+ } else if (item instanceof IDateTimeItem) {
+ ZonedDateTime value = ((IDateTimeItem) item).asZonedDateTime();
+ retval = valueOf(value);
+ } else if (item instanceof IStringItem || item instanceof IUntypedAtomicItem) {
+ try {
+ retval = valueOf(item.asString());
+ } catch (IllegalStateException | InvalidTypeMetapathException ex) {
+ // asString can throw IllegalStateException exception
+ throw new InvalidValueForCastFunctionException(ex);
+ }
+ } else {
+ throw new InvalidValueForCastFunctionException(
+ String.format("unsupported item type '%s'", item.getClass().getName()));
+ }
+ return retval;
}
@Override
- default IDateItem castAsType(IAnyAtomicItem item) {
- return cast(item);
- }
+ IDateItem castAsType(IAnyAtomicItem item);
@Override
default int compareTo(IAnyAtomicItem item) {
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDateTimeItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDateTimeItem.java
index 40088877f..83292573d 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDateTimeItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDateTimeItem.java
@@ -6,13 +6,25 @@
package gov.nist.secauto.metaschema.core.metapath.item.atomic;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
-import gov.nist.secauto.metaschema.core.datatype.object.DateTime;
+import gov.nist.secauto.metaschema.core.datatype.object.AmbiguousDateTime;
+import gov.nist.secauto.metaschema.core.metapath.InvalidTypeMetapathException;
import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.impl.DateTimeWithTimeZoneItemImpl;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.impl.DateTimeWithoutTimeZoneItemImpl;
import java.time.ZonedDateTime;
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * An atomic Metapath item representing a date/time value in the Metapath
+ * system.
+ *
+ * This interface provides functionality for handling date/time values with and
+ * without time zone information, supporting parsing, casting, and comparison
+ * operations. It works in conjunction with {@link AmbiguousDateTime} to
+ * properly handle time zone ambiguity.
+ */
public interface IDateTimeItem extends ITemporalItem {
/**
* Construct a new date/time item using the provided string {@code value}.
@@ -26,25 +38,62 @@ static IDateTimeItem valueOf(@NonNull String value) {
try {
return valueOf(MetaschemaDataTypeProvider.DATE_TIME.parse(value));
} catch (IllegalArgumentException ex) {
- throw new InvalidValueForCastFunctionException(String.format("Unable to parse string value '%s'", value),
+ throw new InvalidTypeMetapathException(
+ null,
+ String.format("Invalid date/time value '%s'. %s",
+ value,
+ ex.getLocalizedMessage()),
ex);
}
}
/**
* Construct a new date/time item using the provided {@code value}.
+ *
+ * This method handles recording if an explicit timezone was provided using the
+ * {@code hasTimeZone} parameter. The {@link AmbiguousDateTime#hasTimeZone()}
+ * method can be called to determine if timezone information is present.
+ *
+ * @param value
+ * a date/time, without time zone information
+ * @param hasTimeZone
+ * {@code true} if the date/time is intended to have an associated time
+ * zone or {@code false} otherwise
+ * @return the new item
+ * @see AmbiguousDateTime for more details on timezone handling
+ */
+ @NonNull
+ static IDateTimeItem valueOf(@NonNull ZonedDateTime value, boolean hasTimeZone) {
+ return hasTimeZone
+ ? valueOf(value)
+ : valueOf(new AmbiguousDateTime(value, false));
+ }
+
+ /**
+ * Construct a new date/time item using the provided {@code value}.
+ *
+ * This method handles recording if an explicit timezone was provided using the
+ * {@link AmbiguousDateTime}. The {@link AmbiguousDateTime#hasTimeZone()} method
+ * can be called to determine if timezone information is present.
*
* @param value
* a date/time, without time zone information
* @return the new item
+ * @see AmbiguousDateTime for more details on timezone handling
*/
@NonNull
- static IDateTimeItem valueOf(@NonNull DateTime value) {
- return new DateTimeWithoutTimeZoneItemImpl(value);
+ static IDateTimeItem valueOf(@NonNull AmbiguousDateTime value) {
+ return value.hasTimeZone()
+ ? valueOf(value.getValue())
+ : new DateTimeWithoutTimeZoneItemImpl(value);
}
/**
* Construct a new date/time item using the provided {@code value}.
+ *
+ * This method handles dates with explicit timezone information using
+ * ZonedDateTime. The timezone is preserved as specified in the input and is
+ * significant for date/time operations and comparisons.
*
* @param value
* a date/time, with time zone information
@@ -67,7 +116,22 @@ static IDateTimeItem valueOf(@NonNull ZonedDateTime value) {
*/
@NonNull
static IDateTimeItem cast(@NonNull IAnyAtomicItem item) {
- return MetaschemaDataTypeProvider.DATE_TIME.cast(item);
+ IDateTimeItem retval;
+ if (item instanceof IDateTimeItem) {
+ retval = (IDateTimeItem) item;
+ } else {
+ try {
+ retval = valueOf(item.asString());
+ } catch (IllegalStateException | InvalidTypeMetapathException ex) {
+ // asString can throw IllegalStateException exception
+ throw new InvalidValueForCastFunctionException(
+ String.format("The value '%s' is not compatible with the type '%s'",
+ item.getValue(),
+ item.getClass().getName()),
+ ex);
+ }
+ }
+ return retval;
}
@Override
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDayTimeDurationItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDayTimeDurationItem.java
index 2d47ba484..42a28ecb2 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDayTimeDurationItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDayTimeDurationItem.java
@@ -6,12 +6,18 @@
package gov.nist.secauto.metaschema.core.metapath.item.atomic;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
+import gov.nist.secauto.metaschema.core.metapath.InvalidTypeMetapathException;
import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.impl.DayTimeDurationItemImpl;
import java.time.Duration;
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * An atomic Metapath item containing a duration data value in days, hours, and
+ * seconds.
+ */
public interface IDayTimeDurationItem extends IDurationItem {
/**
* Construct a new day time duration item using the provided string
@@ -20,13 +26,20 @@ public interface IDayTimeDurationItem extends IDurationItem {
* @param value
* a string representing a day time duration
* @return the new item
+ * @throws InvalidTypeMetapathException
+ * if the provided string value is not a day/time duration value
+ * according to ISO 8601
*/
@NonNull
static IDayTimeDurationItem valueOf(@NonNull String value) {
try {
return valueOf(MetaschemaDataTypeProvider.DAY_TIME_DURATION.parse(value));
} catch (IllegalArgumentException ex) {
- throw new InvalidValueForCastFunctionException(String.format("Unable to parse string value '%s'", value),
+ throw new InvalidTypeMetapathException(
+ null,
+ String.format("Invalid day/time value '%s'. %s",
+ value,
+ ex.getLocalizedMessage()),
ex);
}
}
@@ -55,7 +68,14 @@ static IDayTimeDurationItem valueOf(@NonNull Duration value) {
*/
@NonNull
static IDayTimeDurationItem cast(@NonNull IAnyAtomicItem item) {
- return MetaschemaDataTypeProvider.DAY_TIME_DURATION.cast(item);
+ try {
+ return item instanceof IDayTimeDurationItem
+ ? (IDayTimeDurationItem) item
+ : valueOf(item.asString());
+ } catch (IllegalStateException | InvalidTypeMetapathException ex) {
+ // asString can throw IllegalStateException exception
+ throw new InvalidValueForCastFunctionException(ex);
+ }
}
/**
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDecimalItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDecimalItem.java
index b6e4e9925..a6900b323 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDecimalItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDecimalItem.java
@@ -6,19 +6,25 @@
package gov.nist.secauto.metaschema.core.metapath.item.atomic;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
+import gov.nist.secauto.metaschema.core.metapath.InvalidTypeMetapathException;
import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.impl.DecimalItemImpl;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import edu.umd.cs.findbugs.annotations.NonNull;
-import edu.umd.cs.findbugs.annotations.Nullable;
+/**
+ * An atomic Metapath item containing a decimal data value.
+ */
public interface IDecimalItem extends INumericItem {
- @SuppressWarnings("null")
+ /**
+ * The decimal item with the value "0".
+ */
@NonNull
- IDecimalItem ZERO = valueOf(BigDecimal.ZERO);
+ IDecimalItem ZERO = valueOf(ObjectUtils.notNull(BigDecimal.ZERO));
/**
* Construct a new decimal item using the provided string {@code value}.
@@ -26,13 +32,19 @@ public interface IDecimalItem extends INumericItem {
* @param value
* a string representing a decimal value
* @return the new item
+ * @throws InvalidTypeMetapathException
+ * if the given string is not a decimal value
*/
@NonNull
static IDecimalItem valueOf(@NonNull String value) {
try {
return valueOf(MetaschemaDataTypeProvider.DECIMAL.parse(value));
} catch (IllegalArgumentException ex) {
- throw new InvalidValueForCastFunctionException(String.format("Unable to parse string value '%s'", value),
+ throw new InvalidTypeMetapathException(
+ null,
+ String.format("Invalid decimal value '%s'. %s",
+ value,
+ ex.getLocalizedMessage()),
ex);
}
}
@@ -61,6 +73,18 @@ static IDecimalItem valueOf(double value) {
return valueOf(ObjectUtils.notNull(Double.toString(value)));
}
+ /**
+ * Construct a new decimal item using the provided {@code value}.
+ *
+ * @param value
+ * a double value
+ * @return the new item
+ */
+ @NonNull
+ static IDecimalItem valueOf(boolean value) {
+ return valueOf(DecimalItemImpl.toBigDecimal(value));
+ }
+
/**
* Construct a new decimal item using the provided {@code value}.
*
@@ -84,13 +108,28 @@ static IDecimalItem valueOf(@NonNull BigDecimal value) {
* if the provided {@code item} cannot be cast to this type
*/
@NonNull
- static IDecimalItem cast(@Nullable IAnyAtomicItem item) {
- return MetaschemaDataTypeProvider.DECIMAL.cast(item);
+ static IDecimalItem cast(@NonNull IAnyAtomicItem item) {
+ IDecimalItem retval;
+ if (item instanceof IDecimalItem) {
+ retval = (IDecimalItem) item;
+ } else if (item instanceof INumericItem) {
+ retval = valueOf(((INumericItem) item).asDecimal());
+ } else if (item instanceof IBooleanItem) {
+ retval = valueOf(((IBooleanItem) item).toBoolean());
+ } else {
+ try {
+ retval = valueOf(item.asString());
+ } catch (IllegalStateException | InvalidTypeMetapathException ex) {
+ // asString can throw IllegalStateException exception
+ throw new InvalidValueForCastFunctionException(ex);
+ }
+ }
+ return retval;
}
@Override
default IDecimalItem castAsType(IAnyAtomicItem item) {
- return valueOf(cast(item).asDecimal());
+ return cast(item);
}
@Override
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDurationItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDurationItem.java
index ce9817e24..6b0b7fc7d 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDurationItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IDurationItem.java
@@ -11,6 +11,19 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * An atomic Metapath item representing a duration data value.
+ *
+ * This interface supports both day-time and year-month duration formats
+ * following the ISO 8601 standard. Examples of valid durations include:
+ *
+ * P1Y2M (1 year, 2 months)
+ * P3DT4H5M (3 days, 4 hours, 5 minutes)
+ *
+ *
+ * @see IDayTimeDurationItem
+ * @see IYearMonthDurationItem
+ */
public interface IDurationItem extends IAnyAtomicItem {
/**
* Cast the provided type to this item type.
@@ -28,13 +41,23 @@ static IDurationItem cast(@NonNull IAnyAtomicItem item) {
if (item instanceof IDurationItem) {
retval = (IDurationItem) item;
} else {
+ String value;
+ try {
+ value = item.asString();
+ } catch (IllegalStateException ex) {
+ // asString can throw IllegalStateException exception
+ throw new InvalidValueForCastFunctionException(ex);
+ }
+
try {
- retval = IDayTimeDurationItem.valueOf(item.asString());
+ retval = IDayTimeDurationItem.valueOf(value);
} catch (IllegalStateException ex) {
try {
- retval = IYearMonthDurationItem.valueOf(item.asString());
+ retval = IYearMonthDurationItem.valueOf(value);
} catch (IllegalStateException ex2) {
- InvalidValueForCastFunctionException newEx = new InvalidValueForCastFunctionException(ex2);
+ InvalidValueForCastFunctionException newEx = new InvalidValueForCastFunctionException(
+ String.format("Value '%s' cannot be parsed as either a day-time or year-month duration", value),
+ ex2);
newEx.addSuppressed(ex);
throw newEx; // NOPMD context as suppressed
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IEmailAddressItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IEmailAddressItem.java
index ddfe5d54f..bc54171fc 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IEmailAddressItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IEmailAddressItem.java
@@ -6,10 +6,15 @@
package gov.nist.secauto.metaschema.core.metapath.item.atomic;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
+import gov.nist.secauto.metaschema.core.metapath.InvalidTypeMetapathException;
import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.impl.EmailAddressItemImpl;
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * An atomic Metapath item containing an email address data value.
+ */
public interface IEmailAddressItem extends IStringItem {
/**
* Construct a new email address item using the provided string {@code value}.
@@ -17,13 +22,19 @@ public interface IEmailAddressItem extends IStringItem {
* @param value
* a string representing an email address value
* @return the new item
+ * @throws InvalidTypeMetapathException
+ * if the given string is not an email address value
*/
@NonNull
static IEmailAddressItem valueOf(@NonNull String value) {
try {
return new EmailAddressItemImpl(MetaschemaDataTypeProvider.EMAIL_ADDRESS.parse(value));
} catch (IllegalArgumentException ex) {
- throw new InvalidValueForCastFunctionException(String.format("Unable to parse string value '%s'", value),
+ throw new InvalidTypeMetapathException(
+ null,
+ String.format("Invalid email address value '%s'. %s",
+ value,
+ ex.getLocalizedMessage()),
ex);
}
}
@@ -40,7 +51,14 @@ static IEmailAddressItem valueOf(@NonNull String value) {
*/
@NonNull
static IEmailAddressItem cast(@NonNull IAnyAtomicItem item) {
- return MetaschemaDataTypeProvider.EMAIL_ADDRESS.cast(item);
+ try {
+ return item instanceof IEmailAddressItem
+ ? (IEmailAddressItem) item
+ : valueOf(item.asString());
+ } catch (IllegalStateException | InvalidTypeMetapathException ex) {
+ // asString can throw IllegalStateException exception
+ throw new InvalidValueForCastFunctionException(ex);
+ }
}
@Override
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IHostnameItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IHostnameItem.java
index 61fb7086a..001f1bfc4 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IHostnameItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IHostnameItem.java
@@ -6,16 +6,21 @@
package gov.nist.secauto.metaschema.core.metapath.item.atomic;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
+import gov.nist.secauto.metaschema.core.metapath.InvalidTypeMetapathException;
import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.impl.HostnameItemImpl;
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * An atomic Metapath item containing a hostname data value.
+ */
public interface IHostnameItem extends IStringItem {
/**
* Construct a new host name item using the provided string {@code value}.
*
* @param value
- * a string representing an host name value
+ * a string representing a host name value
* @return the new item
*/
@NonNull
@@ -23,7 +28,11 @@ static IHostnameItem valueOf(@NonNull String value) {
try {
return new HostnameItemImpl(MetaschemaDataTypeProvider.HOSTNAME.parse(value));
} catch (IllegalArgumentException ex) {
- throw new InvalidValueForCastFunctionException(String.format("Unable to parse string value '%s'", value),
+ throw new InvalidTypeMetapathException(
+ null,
+ String.format("Invalid hostname value '%s'. %s",
+ value,
+ ex.getLocalizedMessage()),
ex);
}
}
@@ -40,7 +49,14 @@ static IHostnameItem valueOf(@NonNull String value) {
*/
@NonNull
static IHostnameItem cast(@NonNull IAnyAtomicItem item) {
- return MetaschemaDataTypeProvider.HOSTNAME.cast(item);
+ try {
+ return item instanceof IHostnameItem
+ ? (IHostnameItem) item
+ : valueOf(item.asString());
+ } catch (IllegalStateException | InvalidTypeMetapathException ex) {
+ // asString can throw IllegalStateException exception
+ throw new InvalidValueForCastFunctionException(ex);
+ }
}
@Override
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IIPAddressItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IIPAddressItem.java
index 687f4be5e..59dd04a23 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IIPAddressItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IIPAddressItem.java
@@ -5,9 +5,14 @@
package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
+
import edu.umd.cs.findbugs.annotations.NonNull;
import inet.ipaddr.IPAddress;
+/**
+ * An atomic Metapath item representing an IP address data value.
+ */
public interface IIPAddressItem extends IUntypedAtomicItem {
/**
* Get the "wrapped" IP address value.
@@ -28,4 +33,32 @@ public interface IIPAddressItem extends IUntypedAtomicItem {
default int compareTo(IIPAddressItem item) {
return asIpAddress().compareTo(item.asIpAddress());
}
+
+ /**
+ * Cast the provided type to this item type.
+ *
+ * @param item
+ * the item to cast
+ * @return the original item if it is already this type, otherwise a new item
+ * cast to this type
+ * @throws InvalidValueForCastFunctionException
+ * if the provided {@code item} cannot be cast to this type
+ */
+ @NonNull
+ static IIPAddressItem cast(@NonNull IAnyAtomicItem item) {
+ if (!(item instanceof IIPAddressItem)) {
+ String value = null;
+ try {
+ value = item.asString();
+ } catch (IllegalStateException ex) {
+ // do nothing. this is a best effort to get the value
+ }
+
+ throw new InvalidValueForCastFunctionException(
+ String.format("The value '%s' of type '%s' is not an internet protocol address.",
+ value == null ? "(unknown)" : value,
+ item.getJavaTypeAdapter().getPreferredName()));
+ }
+ return (IIPAddressItem) item;
+ }
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IIPv4AddressItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IIPv4AddressItem.java
index e24c1c9d3..7de02e6f5 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IIPv4AddressItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IIPv4AddressItem.java
@@ -6,13 +6,39 @@
package gov.nist.secauto.metaschema.core.metapath.item.atomic;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
+import gov.nist.secauto.metaschema.core.metapath.InvalidTypeMetapathException;
import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.impl.IPv4AddressItemImpl;
import edu.umd.cs.findbugs.annotations.NonNull;
import inet.ipaddr.ipv4.IPv4Address;
+/**
+ * An atomic Metapath item containing an IPv4 address data value.
+ */
public interface IIPv4AddressItem extends IIPAddressItem {
+ /**
+ * Construct a new IPv4 item using the provided {@code value}.
+ *
+ * @param value
+ * an IPv4 value
+ * @return the new item
+ */
+ @NonNull
+ static IIPv4AddressItem valueOf(@NonNull String value) {
+ try {
+ return valueOf(MetaschemaDataTypeProvider.IP_V4_ADDRESS.parse(value));
+ } catch (IllegalArgumentException ex) {
+ throw new InvalidTypeMetapathException(
+ null,
+ String.format("Invalid IPv4 address value '%s'. %s",
+ value,
+ ex.getLocalizedMessage()),
+ ex);
+ }
+ }
+
/**
* Construct a new IPv4 item using the provided {@code value}.
*
@@ -37,7 +63,14 @@ static IIPv4AddressItem valueOf(@NonNull IPv4Address value) {
*/
@NonNull
static IIPv4AddressItem cast(@NonNull IAnyAtomicItem item) {
- return MetaschemaDataTypeProvider.IP_V4_ADDRESS.cast(item);
+ try {
+ return item instanceof IIPv4AddressItem
+ ? (IIPv4AddressItem) item
+ : valueOf(item.asString());
+ } catch (IllegalStateException | InvalidTypeMetapathException ex) {
+ // asString can throw IllegalStateException exception
+ throw new InvalidValueForCastFunctionException(ex);
+ }
}
@Override
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IIPv6AddressItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IIPv6AddressItem.java
index 23edb002c..82c3234a8 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IIPv6AddressItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IIPv6AddressItem.java
@@ -6,13 +6,39 @@
package gov.nist.secauto.metaschema.core.metapath.item.atomic;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
+import gov.nist.secauto.metaschema.core.metapath.InvalidTypeMetapathException;
import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.impl.IPv6AddressItemImpl;
import edu.umd.cs.findbugs.annotations.NonNull;
import inet.ipaddr.ipv6.IPv6Address;
+/**
+ * An atomic Metapath item containing an IPv6 address data value.
+ */
public interface IIPv6AddressItem extends IIPAddressItem {
+ /**
+ * Construct a new IPv6 item using the provided {@code value}.
+ *
+ * @param value
+ * an IPv6 value
+ * @return the new item
+ */
+ @NonNull
+ static IIPv6AddressItem valueOf(@NonNull String value) {
+ try {
+ return valueOf(MetaschemaDataTypeProvider.IP_V6_ADDRESS.parse(value));
+ } catch (IllegalArgumentException ex) {
+ throw new InvalidTypeMetapathException(
+ null,
+ String.format("Invalid IPv6 address value '%s'. %s",
+ value,
+ ex.getLocalizedMessage()),
+ ex);
+ }
+ }
+
/**
* Construct a new IPv6 item using the provided {@code value}.
*
@@ -37,7 +63,14 @@ static IIPv6AddressItem valueOf(@NonNull IPv6Address value) {
*/
@NonNull
static IIPv6AddressItem cast(@NonNull IAnyAtomicItem item) {
- return MetaschemaDataTypeProvider.IP_V6_ADDRESS.cast(item);
+ try {
+ return item instanceof IIPv6AddressItem
+ ? (IIPv6AddressItem) item
+ : valueOf(item.asString());
+ } catch (IllegalStateException | InvalidTypeMetapathException ex) {
+ // asString can throw IllegalStateException exception
+ throw new InvalidValueForCastFunctionException(ex);
+ }
}
@Override
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IIntegerItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IIntegerItem.java
index db6b14002..8190df2eb 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IIntegerItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IIntegerItem.java
@@ -5,25 +5,34 @@
package gov.nist.secauto.metaschema.core.metapath.item.atomic;
-import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
import gov.nist.secauto.metaschema.core.metapath.InvalidTypeMetapathException;
import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.impl.IntegerItemImpl;
+import gov.nist.secauto.metaschema.core.util.ObjectUtils;
import java.math.BigInteger;
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * An atomic Metapath item containing an integer data value.
+ */
public interface IIntegerItem extends IDecimalItem {
-
- @SuppressWarnings("null")
+ /**
+ * The integer value "1".
+ */
@NonNull
- IIntegerItem ONE = valueOf(BigInteger.ONE);
- @SuppressWarnings("null")
+ IIntegerItem ONE = valueOf(ObjectUtils.notNull(BigInteger.ONE));
+ /**
+ * The integer value "0".
+ */
@NonNull
- IIntegerItem ZERO = valueOf(BigInteger.ZERO);
- @SuppressWarnings("null")
+ IIntegerItem ZERO = valueOf(ObjectUtils.notNull(BigInteger.ZERO));
+ /**
+ * The integer value "-1".
+ */
@NonNull
- IIntegerItem NEGATIVE_ONE = valueOf(BigInteger.ONE.negate());
+ IIntegerItem NEGATIVE_ONE = valueOf(ObjectUtils.notNull(BigInteger.ONE.negate()));
/**
* Create an item from an existing integer value.
@@ -75,6 +84,18 @@ static IIntegerItem valueOf(long value) {
return valueOf(bigInteger);
}
+ /**
+ * Construct a new integer item using the provided {@code value}.
+ *
+ * @param value
+ * a long value
+ * @return the new item
+ */
+ @NonNull
+ static IIntegerItem valueOf(boolean value) {
+ return valueOf(ObjectUtils.notNull(value ? BigInteger.ONE : BigInteger.ZERO));
+ }
+
/**
* Construct a new integer item using the provided {@code value}.
*
@@ -109,7 +130,27 @@ static IIntegerItem valueOf(@NonNull BigInteger value) {
*/
@NonNull
static IIntegerItem cast(@NonNull IAnyAtomicItem item) {
- return MetaschemaDataTypeProvider.INTEGER.cast(item);
+ IIntegerItem retval;
+ if (item instanceof IIntegerItem) {
+ retval = (IIntegerItem) item;
+ } else if (item instanceof INumericItem) {
+ retval = valueOf(((INumericItem) item).asInteger());
+ } else if (item instanceof IBooleanItem) {
+ retval = valueOf(((IBooleanItem) item).toBoolean());
+ } else {
+ try {
+ retval = valueOf(item.asString());
+ } catch (IllegalStateException | InvalidTypeMetapathException ex) {
+ // asString can throw IllegalStateException exception
+ throw new InvalidValueForCastFunctionException(ex);
+ }
+ }
+ return retval;
+ }
+
+ @Override
+ default IIntegerItem castAsType(IAnyAtomicItem item) {
+ return cast(item);
}
@Override
@@ -125,11 +166,6 @@ default IIntegerItem floor() {
return this;
}
- @Override
- default IIntegerItem castAsType(IAnyAtomicItem item) {
- return valueOf(cast(item).asInteger());
- }
-
@Override
default int compareTo(IAnyAtomicItem item) {
return compareTo(cast(item));
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IMarkupItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IMarkupItem.java
index 22f450021..c6bbc0e17 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IMarkupItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IMarkupItem.java
@@ -9,11 +9,34 @@
import gov.nist.secauto.metaschema.core.datatype.markup.MarkupDataTypeProvider;
import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine;
import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline;
+import gov.nist.secauto.metaschema.core.metapath.InvalidTypeMetapathException;
import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.impl.MarkupLineItemImpl;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.impl.MarkupMultiLineItemImpl;
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * An atomic Metapath item representing a Markup data value.
+ */
public interface IMarkupItem extends IUntypedAtomicItem {
+ /**
+ * Construct a new item using the provided {@code value}.
+ *
+ * @param value
+ * a line of markup
+ * @return the new item
+ */
+ @SuppressWarnings("PMD.AvoidCatchingGenericException")
+ @NonNull
+ static IMarkupItem valueOf(@NonNull String value) {
+ try {
+ return valueOf(MarkupDataTypeProvider.MARKUP_LINE.parse(value));
+ } catch (IllegalArgumentException ex) {
+ throw new InvalidValueForCastFunctionException(ex);
+ }
+ }
+
/**
* Construct a new item using the provided {@code value}.
*
@@ -50,7 +73,14 @@ static IMarkupItem valueOf(@NonNull MarkupMultiline value) {
*/
@NonNull
static IMarkupItem cast(@NonNull IAnyAtomicItem item) {
- return MarkupDataTypeProvider.MARKUP_MULTILINE.cast(item);
+ try {
+ return item instanceof IMarkupItem
+ ? (IMarkupItem) item
+ : valueOf(item.asString());
+ } catch (IllegalStateException | InvalidTypeMetapathException ex) {
+ // asString can throw IllegalStateException exception
+ throw new InvalidValueForCastFunctionException(ex);
+ }
}
/**
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/INcNameItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/INcNameItem.java
index e26b346f8..3253d8d2d 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/INcNameItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/INcNameItem.java
@@ -6,10 +6,15 @@
package gov.nist.secauto.metaschema.core.metapath.item.atomic;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
+import gov.nist.secauto.metaschema.core.metapath.InvalidTypeMetapathException;
import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.impl.NcNameItemImpl;
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * An atomic Metapath item containing a non-colonized name (NCName) data value.
+ */
@Deprecated(forRemoval = true, since = "0.7.0")
public interface INcNameItem extends IStringItem {
/**
@@ -25,7 +30,11 @@ static INcNameItem valueOf(@NonNull String value) {
try {
return new NcNameItemImpl(MetaschemaDataTypeProvider.NCNAME.parse(value));
} catch (IllegalArgumentException ex) {
- throw new InvalidValueForCastFunctionException(String.format("Unable to parse string value '%s'", value),
+ throw new InvalidTypeMetapathException(
+ null,
+ String.format("Invalid non-colonized name value '%s'. %s",
+ value,
+ ex.getLocalizedMessage()),
ex);
}
}
@@ -42,7 +51,14 @@ static INcNameItem valueOf(@NonNull String value) {
*/
@NonNull
static INcNameItem cast(@NonNull IAnyAtomicItem item) {
- return MetaschemaDataTypeProvider.NCNAME.cast(item);
+ try {
+ return item instanceof INcNameItem
+ ? (INcNameItem) item
+ : valueOf(item.asString());
+ } catch (IllegalStateException | InvalidTypeMetapathException ex) {
+ // asString can throw IllegalStateException exception
+ throw new InvalidValueForCastFunctionException(ex);
+ }
}
@Override
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/INonNegativeIntegerItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/INonNegativeIntegerItem.java
index b346796e9..d24dcdc16 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/INonNegativeIntegerItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/INonNegativeIntegerItem.java
@@ -8,18 +8,27 @@
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
import gov.nist.secauto.metaschema.core.metapath.InvalidTypeMetapathException;
import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.impl.NonNegativeIntegerItemImpl;
+import gov.nist.secauto.metaschema.core.util.ObjectUtils;
import java.math.BigInteger;
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * An atomic Metapath item containing a non-negative integer data value.
+ */
public interface INonNegativeIntegerItem extends IIntegerItem {
- @SuppressWarnings("null")
+ /**
+ * The integer value "1".
+ */
@NonNull
- INonNegativeIntegerItem ONE = valueOf(BigInteger.ONE);
- @SuppressWarnings("null")
+ INonNegativeIntegerItem ONE = valueOf(ObjectUtils.notNull(BigInteger.ONE));
+ /**
+ * The integer value "0".
+ */
@NonNull
- INonNegativeIntegerItem ZERO = valueOf(BigInteger.ZERO);
+ INonNegativeIntegerItem ZERO = valueOf(ObjectUtils.notNull(BigInteger.ZERO));
/**
* Create an item from an existing integer value.
@@ -33,10 +42,13 @@ public interface INonNegativeIntegerItem extends IIntegerItem {
@NonNull
static INonNegativeIntegerItem valueOf(@NonNull String value) {
try {
- return valueOf(new BigInteger(value));
- } catch (NumberFormatException ex) {
- throw new InvalidTypeMetapathException(null,
- ex.getMessage(),
+ return valueOf(MetaschemaDataTypeProvider.NON_NEGATIVE_INTEGER.parse(value));
+ } catch (IllegalArgumentException ex) {
+ throw new InvalidTypeMetapathException(
+ null,
+ String.format("Invalid non-negative integer value '%s'. %s",
+ value,
+ ex.getLocalizedMessage()),
ex);
}
}
@@ -51,7 +63,7 @@ static INonNegativeIntegerItem valueOf(@NonNull String value) {
* if the provided value is not a non-negative integer
*/
@NonNull
- static INonNegativeIntegerItem valueOf(@NonNull IIntegerItem value) {
+ static INonNegativeIntegerItem valueOf(@NonNull INumericItem value) {
return valueOf(value.asInteger());
}
@@ -84,7 +96,7 @@ static INonNegativeIntegerItem valueOf(@NonNull BigInteger value) {
if (value.compareTo(BigInteger.ZERO) < 0) {
throw new InvalidTypeMetapathException(
null,
- String.format("Integer value '%s' is negative.", value));
+ String.format("Integer value '%s' must not be negative.", value));
}
return new NonNegativeIntegerItemImpl(value);
}
@@ -101,11 +113,19 @@ static INonNegativeIntegerItem valueOf(@NonNull BigInteger value) {
*/
@NonNull
static INonNegativeIntegerItem cast(@NonNull IAnyAtomicItem item) {
- return MetaschemaDataTypeProvider.NON_NEGATIVE_INTEGER.cast(item);
+ try {
+ return item instanceof INonNegativeIntegerItem
+ ? (INonNegativeIntegerItem) item
+ : item instanceof INumericItem
+ ? valueOf((INumericItem) item)
+ : valueOf(item.asString());
+ } catch (InvalidTypeMetapathException ex) {
+ throw new InvalidValueForCastFunctionException(ex);
+ }
}
@Override
default INonNegativeIntegerItem castAsType(IAnyAtomicItem item) {
- return valueOf(cast(item).asInteger());
+ return cast(item);
}
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/INumericItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/INumericItem.java
index 6bab669ca..2ea3b0f10 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/INumericItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/INumericItem.java
@@ -5,7 +5,7 @@
package gov.nist.secauto.metaschema.core.metapath.item.atomic;
-import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
+import gov.nist.secauto.metaschema.core.metapath.InvalidTypeMetapathException;
import gov.nist.secauto.metaschema.core.metapath.function.ArithmeticFunctionException;
import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils;
import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
@@ -18,6 +18,15 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * Represents an atomic Metapath item containing a numeric data value, which can
+ * be either an integer or decimal. This interface provides operations for
+ * numeric type conversion, comparison, and mathematical operations commonly
+ * used in Metapath expressions.
+ *
+ * @see IIntegerItem
+ * @see IDecimalItem
+ */
public interface INumericItem extends IAnyAtomicItem {
/**
@@ -32,7 +41,14 @@ public interface INumericItem extends IAnyAtomicItem {
*/
@NonNull
static INumericItem cast(@NonNull IAnyAtomicItem item) {
- return MetaschemaDataTypeProvider.DECIMAL.cast(item);
+ try {
+ return item instanceof INumericItem
+ ? (INumericItem) item
+ : IDecimalItem.valueOf(item.asString());
+ } catch (IllegalStateException | InvalidTypeMetapathException ex) {
+ // asString can throw IllegalStateException exception
+ throw new InvalidValueForCastFunctionException(ex);
+ }
}
/**
@@ -110,7 +126,6 @@ default INumericItem round() {
* (negative value} or after (positive value) the decimal point.
* @return the rounded value
*/
- @SuppressWarnings("PMD.CognitiveComplexity") // ok
@NonNull
default INumericItem round(@NonNull IIntegerItem precisionItem) {
int precision;
@@ -120,44 +135,51 @@ default INumericItem round(@NonNull IIntegerItem precisionItem) {
throw new ArithmeticFunctionException(ArithmeticFunctionException.OVERFLOW_UNDERFLOW_ERROR,
"Numeric operation overflow/underflow.", ex);
}
+ return precision >= 0
+ ? roundWithPositivePrecision(precision)
+ : roundWithNegativePrecision(precision);
+ }
+
+ @NonNull
+ private INumericItem roundWithPositivePrecision(int precision) {
+ INumericItem retval;
+ if (this instanceof IIntegerItem) {
+ retval = this;
+ } else {
+ BigDecimal value = asDecimal();
+ BigDecimal rounded = value.signum() == -1
+ ? value.round(new MathContext(precision + value.precision() - value.scale(), RoundingMode.HALF_DOWN))
+ : value.round(new MathContext(precision + value.precision() - value.scale(), RoundingMode.HALF_UP));
+ retval = castAsType(IDecimalItem.valueOf(ObjectUtils.notNull(rounded)));
+ }
+ return retval;
+ }
+
+ /**
+ * Rounds a number to the specified negative precision by: 1. Computing the
+ * divisor (10^|precision|) 2. If the absolute value is less than the divisor,
+ * returns 0 3. Otherwise, rounds to the nearest multiple of the divisor
+ *
+ * @param precision
+ * the negative precision to round to
+ * @return the rounded value
+ */
+ @NonNull
+ private INumericItem roundWithNegativePrecision(int precision) {
+ BigInteger value = asInteger();
+ BigInteger divisor = BigInteger.TEN.pow(0 - precision);
+
INumericItem retval;
- if (precision >= 0) {
- // round to precision decimal places
- if (this instanceof IIntegerItem) {
- retval = this;
- } else {
- // IDecimalItem
- BigDecimal value = asDecimal();
- if (value.signum() == -1) {
- retval = IDecimalItem.valueOf(
- ObjectUtils.notNull(
- value.round(new MathContext(precision + value.precision() - value.scale(), RoundingMode.HALF_DOWN))));
- } else {
- retval = IDecimalItem.valueOf(
- ObjectUtils.notNull(
- value.round(new MathContext(precision + value.precision() - value.scale(), RoundingMode.HALF_UP))));
- }
-
- // cast result to original type
- retval = castAsType(retval);
- }
+ if (divisor.compareTo(value.abs()) > 0) {
+ retval = IIntegerItem.ZERO;
} else {
- // round to a power of 10
- BigInteger value = asInteger();
- BigInteger divisor = BigInteger.TEN.pow(0 - precision);
-
- @NonNull
- BigInteger result;
- if (divisor.compareTo(value.abs()) > 0) {
- result = ObjectUtils.notNull(BigInteger.ZERO);
- } else {
- BigInteger remainder = value.mod(divisor);
- BigInteger lessRemainder = value.subtract(remainder);
- BigInteger halfDivisor = divisor.divide(BigInteger.TWO);
- result = ObjectUtils.notNull(
- remainder.compareTo(halfDivisor) >= 0 ? lessRemainder.add(divisor) : lessRemainder);
- }
- retval = IIntegerItem.valueOf(result);
+ BigInteger remainder = value.mod(divisor);
+ BigInteger lessRemainder = value.subtract(remainder);
+ BigInteger halfDivisor = divisor.divide(BigInteger.TWO);
+ BigInteger roundedValue = remainder.compareTo(halfDivisor) >= 0
+ ? lessRemainder.add(divisor)
+ : lessRemainder;
+ retval = IIntegerItem.valueOf(ObjectUtils.notNull(roundedValue));
}
return retval;
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IPositiveIntegerItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IPositiveIntegerItem.java
index 7eff6798c..51014d7f0 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IPositiveIntegerItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IPositiveIntegerItem.java
@@ -5,15 +5,21 @@
package gov.nist.secauto.metaschema.core.metapath.item.atomic;
-import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
import gov.nist.secauto.metaschema.core.metapath.InvalidTypeMetapathException;
import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.impl.PositiveIntegerItemImpl;
import java.math.BigInteger;
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * An atomic Metapath item containing a positive integer data value.
+ */
public interface IPositiveIntegerItem extends INonNegativeIntegerItem {
+ /**
+ * The integer value "1".
+ */
@SuppressWarnings("null")
@NonNull
IPositiveIntegerItem ONE = valueOf(BigInteger.ONE);
@@ -31,9 +37,12 @@ public interface IPositiveIntegerItem extends INonNegativeIntegerItem {
static IPositiveIntegerItem valueOf(@NonNull String value) {
try {
return valueOf(new BigInteger(value));
- } catch (NumberFormatException ex) {
- throw new InvalidTypeMetapathException(null,
- ex.getMessage(),
+ } catch (IllegalArgumentException ex) {
+ throw new InvalidTypeMetapathException(
+ null,
+ String.format("Invalid positive integer value '%s'. %s",
+ value,
+ ex.getLocalizedMessage()),
ex);
}
}
@@ -48,7 +57,7 @@ static IPositiveIntegerItem valueOf(@NonNull String value) {
* if the provided value is not a positive integer
*/
@NonNull
- static IPositiveIntegerItem valueOf(@NonNull IIntegerItem value) {
+ static IPositiveIntegerItem valueOf(@NonNull INumericItem value) {
return valueOf(value.asInteger());
}
@@ -98,11 +107,20 @@ static IPositiveIntegerItem valueOf(@NonNull BigInteger value) {
*/
@NonNull
static IPositiveIntegerItem cast(@NonNull IAnyAtomicItem item) {
- return MetaschemaDataTypeProvider.POSITIVE_INTEGER.cast(item);
+ try {
+ return item instanceof IPositiveIntegerItem
+ ? (IPositiveIntegerItem) item
+ : item instanceof INumericItem
+ ? valueOf((INumericItem) item)
+ : valueOf(item.asString());
+ } catch (IllegalStateException | InvalidTypeMetapathException ex) {
+ // asString can throw IllegalStateException exception
+ throw new InvalidValueForCastFunctionException(ex);
+ }
}
@Override
default IPositiveIntegerItem castAsType(IAnyAtomicItem item) {
- return valueOf(cast(item).asInteger());
+ return cast(item);
}
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IStringItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IStringItem.java
index b1d7de5c5..3742a9414 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IStringItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IStringItem.java
@@ -5,21 +5,39 @@
package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
+import gov.nist.secauto.metaschema.core.metapath.InvalidTypeMetapathException;
import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.impl.StringItemImpl;
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * An atomic Metapath item containing a text data value.
+ */
public interface IStringItem extends IAnyAtomicItem {
/**
* Construct a new item using the provided string {@code value}.
*
* @param value
- * a string value
+ * a string value that must conform to Metaschema string validation
+ * rules
* @return the new item
+ * @throws InvalidTypeMetapathException
+ * if the value fails string validation
*/
@NonNull
static IStringItem valueOf(@NonNull String value) {
- return new StringItemImpl(value);
+ try {
+ return new StringItemImpl(MetaschemaDataTypeProvider.STRING.parse(value));
+ } catch (IllegalArgumentException ex) {
+ throw new InvalidTypeMetapathException(
+ null,
+ String.format("Invalid string value '%s'. %s",
+ value,
+ ex.getLocalizedMessage()),
+ ex);
+ }
}
/**
@@ -35,9 +53,12 @@ static IStringItem valueOf(@NonNull String value) {
@NonNull
static IStringItem cast(@NonNull IAnyAtomicItem item) {
try {
- return item.asStringItem();
+ return item instanceof IStringItem
+ ? (IStringItem) item
+ : valueOf(item.asString());
} catch (IllegalStateException ex) {
- throw new InvalidValueForCastFunctionException(ex.getLocalizedMessage(), ex);
+ // asString can throw IllegalStateException exception
+ throw new InvalidValueForCastFunctionException(ex);
}
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/ITemporalItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/ITemporalItem.java
index f95bd0ebc..f60a6e16a 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/ITemporalItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/ITemporalItem.java
@@ -9,6 +9,9 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * An atomic Metapath item containing a temporal data value.
+ */
public interface ITemporalItem extends IAnyAtomicItem {
/**
* Determine if the temporal item has a timezone.
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/ITokenItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/ITokenItem.java
index 9de2438e3..9dacff82e 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/ITokenItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/ITokenItem.java
@@ -6,10 +6,15 @@
package gov.nist.secauto.metaschema.core.metapath.item.atomic;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
+import gov.nist.secauto.metaschema.core.metapath.InvalidTypeMetapathException;
import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.impl.TokenItemImpl;
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * An atomic Metapath item containing a text token data value.
+ */
public interface ITokenItem extends IStringItem {
/**
* Construct a new item using the provided string {@code value}.
@@ -17,13 +22,19 @@ public interface ITokenItem extends IStringItem {
* @param value
* a string representing a token value
* @return the new item
+ * @throws InvalidTypeMetapathException
+ * if the provided value is not a token
*/
@NonNull
static ITokenItem valueOf(@NonNull String value) {
try {
return new TokenItemImpl(MetaschemaDataTypeProvider.TOKEN.parse(value));
} catch (IllegalArgumentException ex) {
- throw new InvalidValueForCastFunctionException(String.format("Unable to parse string value '%s'", value),
+ throw new InvalidTypeMetapathException(
+ null,
+ String.format("Invalid token value '%s'. %s",
+ value,
+ ex.getLocalizedMessage()),
ex);
}
}
@@ -40,7 +51,13 @@ static ITokenItem valueOf(@NonNull String value) {
*/
@NonNull
static ITokenItem cast(@NonNull IAnyAtomicItem item) {
- return MetaschemaDataTypeProvider.TOKEN.cast(item);
+ try {
+ return item instanceof ITokenItem
+ ? (ITokenItem) item
+ : valueOf(item.asString());
+ } catch (InvalidTypeMetapathException ex) {
+ throw new InvalidValueForCastFunctionException(ex);
+ }
}
@Override
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IUntypedAtomicItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IUntypedAtomicItem.java
index fc73fec57..af125d870 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IUntypedAtomicItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IUntypedAtomicItem.java
@@ -5,6 +5,9 @@
package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+/**
+ * An atomic Metapath item containing an untyped atomic data value.
+ */
public interface IUntypedAtomicItem extends IAnyAtomicItem {
// this interface has no additional methods
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IUriReferenceItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IUriReferenceItem.java
index 6a40b728a..ef17d7001 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IUriReferenceItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IUriReferenceItem.java
@@ -6,13 +6,46 @@
package gov.nist.secauto.metaschema.core.metapath.item.atomic;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
+import gov.nist.secauto.metaschema.core.metapath.InvalidTypeMetapathException;
import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.impl.UriReferenceItemImpl;
import java.net.URI;
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * An atomic Metapath item containing a URI reference data value that complies
+ * with RFC2396. URI references can be absolute URIs, relative URIs, or
+ * same-document references.
+ *
+ * @see java.net.URI
+ * @see RFC2396
+ */
public interface IUriReferenceItem extends IAnyUriItem {
+ /**
+ * Construct a new URI item using the provided string {@code value}.
+ *
+ * @param value
+ * a string representing a URI
+ * @return the new item
+ * @throws InvalidTypeMetapathException
+ * if the given string violates RFC2396
+ */
+ @NonNull
+ static IUriReferenceItem valueOf(@NonNull String value) {
+ try {
+ return valueOf(MetaschemaDataTypeProvider.URI_REFERENCE.parse(value));
+ } catch (IllegalArgumentException ex) {
+ throw new InvalidTypeMetapathException(
+ null,
+ String.format("Invalid URI reference value '%s'. %s",
+ value,
+ ex.getLocalizedMessage()),
+ ex);
+ }
+ }
+
/**
* Construct a new item using the provided URI {@code value}.
*
@@ -37,7 +70,16 @@ static IUriReferenceItem valueOf(@NonNull URI value) {
*/
@NonNull
static IUriReferenceItem cast(@NonNull IAnyAtomicItem item) {
- return MetaschemaDataTypeProvider.URI_REFERENCE.cast(item);
+ try {
+ return item instanceof IUriReferenceItem
+ ? (IUriReferenceItem) item
+ : item instanceof IAnyUriItem
+ ? valueOf(((IAnyUriItem) item).asUri())
+ : valueOf(item.asString());
+ } catch (IllegalStateException | InvalidTypeMetapathException ex) {
+ // asString can throw IllegalStateException exception
+ throw new InvalidValueForCastFunctionException(ex);
+ }
}
@Override
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IUuidItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IUuidItem.java
index b942c823c..134a84d69 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IUuidItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IUuidItem.java
@@ -6,13 +6,40 @@
package gov.nist.secauto.metaschema.core.metapath.item.atomic;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
+import gov.nist.secauto.metaschema.core.metapath.InvalidTypeMetapathException;
import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.impl.UuidItemImpl;
import java.util.UUID;
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * An atomic Metapath item containing a UUID data value.
+ */
public interface IUuidItem extends IStringItem {
+ /**
+ * Construct a new UUID item using the provided string {@code value}.
+ *
+ * @param value
+ * a string representing a UUID
+ * @return the new item
+ * @throws InvalidTypeMetapathException
+ * if the given string violates RFC4122
+ */
+ @NonNull
+ static IUuidItem valueOf(@NonNull String value) {
+ try {
+ return valueOf(MetaschemaDataTypeProvider.UUID.parse(value));
+ } catch (IllegalArgumentException ex) {
+ throw new InvalidTypeMetapathException(
+ null,
+ String.format("Invalid UUID value '%s'. %s",
+ value,
+ ex.getLocalizedMessage()),
+ ex);
+ }
+ }
/**
* Construct a new item using the provided {@code value}.
@@ -49,7 +76,14 @@ static IUuidItem random() {
*/
@NonNull
static IUuidItem cast(@NonNull IAnyAtomicItem item) {
- return MetaschemaDataTypeProvider.UUID.cast(item);
+ try {
+ return item instanceof IUuidItem
+ ? (IUuidItem) item
+ : valueOf(item.asString());
+ } catch (IllegalStateException | InvalidTypeMetapathException ex) {
+ // asString can throw IllegalStateException exception
+ throw new InvalidValueForCastFunctionException(ex);
+ }
}
/**
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IYearMonthDurationItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IYearMonthDurationItem.java
index 20bd2066f..3cffc2934 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IYearMonthDurationItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IYearMonthDurationItem.java
@@ -6,13 +6,18 @@
package gov.nist.secauto.metaschema.core.metapath.item.atomic;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
+import gov.nist.secauto.metaschema.core.metapath.InvalidTypeMetapathException;
import gov.nist.secauto.metaschema.core.metapath.function.InvalidValueForCastFunctionException;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.impl.YearMonthDurationItemImpl;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
import java.time.Period;
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * An atomic Metapath item containing a duration data value in years and months.
+ */
public interface IYearMonthDurationItem extends IDurationItem {
/**
* Construct a new year month day duration item using the provided string
@@ -21,6 +26,9 @@ public interface IYearMonthDurationItem extends IDurationItem {
* @param value
* a string representing a year month day duration
* @return the new item
+ * @throws InvalidTypeMetapathException
+ * if the provided string value is not a day/time duration value
+ * according to ISO 8601
*/
@NonNull
static IYearMonthDurationItem valueOf(@NonNull String value) {
@@ -28,7 +36,11 @@ static IYearMonthDurationItem valueOf(@NonNull String value) {
Period period = ObjectUtils.notNull(MetaschemaDataTypeProvider.YEAR_MONTH_DURATION.parse(value).withDays(0));
return valueOf(period);
} catch (IllegalArgumentException ex) {
- throw new InvalidValueForCastFunctionException(String.format("Unable to parse string value '%s'", value),
+ throw new InvalidTypeMetapathException(
+ null,
+ String.format("Invalid year/month duration value '%s'. %s",
+ value,
+ ex.getLocalizedMessage()),
ex);
}
}
@@ -55,10 +67,9 @@ static IYearMonthDurationItem valueOf(@NonNull Period value) {
* the number of months in the period
* @return the new item
*/
- @SuppressWarnings("null")
@NonNull
static IYearMonthDurationItem valueOf(int years, int months) {
- return valueOf(Period.of(years, months, 0));
+ return valueOf(ObjectUtils.notNull(Period.of(years, months, 0)));
}
/**
@@ -73,7 +84,14 @@ static IYearMonthDurationItem valueOf(int years, int months) {
*/
@NonNull
static IYearMonthDurationItem cast(@NonNull IAnyAtomicItem item) {
- return MetaschemaDataTypeProvider.YEAR_MONTH_DURATION.cast(item);
+ try {
+ return item instanceof IYearMonthDurationItem
+ ? (IYearMonthDurationItem) item
+ : valueOf(item.asString());
+ } catch (IllegalStateException | InvalidTypeMetapathException ex) {
+ // asString can throw IllegalStateException exception
+ throw new InvalidValueForCastFunctionException(ex);
+ }
}
/**
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractDateItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/AbstractDateItem.java
similarity index 56%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractDateItem.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/AbstractDateItem.java
index 35d2a708c..839c1b9c7 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractDateItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/AbstractDateItem.java
@@ -3,10 +3,20 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
+
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IDateItem;
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * An abstract implementation of a Metapath atomic item containing a date data
+ * value.
+ *
+ * @param
+ * the Java type of the wrapped value
+ */
public abstract class AbstractDateItem
extends AbstractTemporalItem
implements IDateItem {
@@ -25,6 +35,11 @@ public boolean hasTimezone() {
return true;
}
+ @Override
+ public IDateItem castAsType(IAnyAtomicItem item) {
+ return IDateItem.cast(item);
+ }
+
@Override
public int hashCode() {
return asZonedDateTime().hashCode();
@@ -34,6 +49,6 @@ public int hashCode() {
@Override
public boolean equals(Object obj) {
return this == obj
- || (obj instanceof IDateItem && compareTo((IDateItem) obj) == 0);
+ || obj instanceof IDateItem && compareTo((IDateItem) obj) == 0;
}
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractDateTimeItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/AbstractDateTimeItem.java
similarity index 55%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractDateTimeItem.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/AbstractDateTimeItem.java
index 0e363d8ab..ea66ba041 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractDateTimeItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/AbstractDateTimeItem.java
@@ -3,10 +3,20 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
+
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IDateTimeItem;
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * An abstract implementation of a Metapath atomic item containing a date/time
+ * data value.
+ *
+ * @param
+ * the Java type of the wrapped value
+ */
public abstract class AbstractDateTimeItem
extends AbstractTemporalItem
implements IDateTimeItem {
@@ -25,6 +35,11 @@ public boolean hasTimezone() {
return true;
}
+ @Override
+ public IDateTimeItem castAsType(IAnyAtomicItem item) {
+ return IDateTimeItem.cast(item);
+ }
+
@Override
public int hashCode() {
return asZonedDateTime().hashCode();
@@ -34,6 +49,6 @@ public int hashCode() {
@Override
public boolean equals(Object obj) {
return this == obj
- || (obj instanceof IDateTimeItem && compareTo((IDateTimeItem) obj) == 0);
+ || obj instanceof IDateTimeItem && compareTo((IDateTimeItem) obj) == 0;
}
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractDecimalItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/AbstractDecimalItem.java
similarity index 66%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractDecimalItem.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/AbstractDecimalItem.java
index 78a5ab290..0d026d9f5 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractDecimalItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/AbstractDecimalItem.java
@@ -3,12 +3,21 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.AbstractAnyAtomicItem;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IDecimalItem;
import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey;
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * An abstract implementation of a Metapath atomic item containing a decimal
+ * data value.
+ *
+ * @param
+ * the Java type of the wrapped value
+ */
public abstract class AbstractDecimalItem
extends AbstractAnyAtomicItem
implements IDecimalItem {
@@ -44,8 +53,8 @@ public int hashCode() {
@Override
public boolean equals(Object obj) {
return this == obj ||
- (obj instanceof AbstractDecimalItem.MapKey
- && getKey().asDecimal().equals(((AbstractDecimalItem>.MapKey) obj).getKey().asDecimal()));
+ obj instanceof AbstractDecimalItem.MapKey
+ && getKey().asDecimal().equals(((AbstractDecimalItem>.MapKey) obj).getKey().asDecimal());
}
}
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractIntegerItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/AbstractIntegerItem.java
similarity index 79%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractIntegerItem.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/AbstractIntegerItem.java
index 051ea784f..a408137a4 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractIntegerItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/AbstractIntegerItem.java
@@ -3,7 +3,9 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
+
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IIntegerItem;
import java.math.BigDecimal;
import java.math.BigInteger;
@@ -11,6 +13,10 @@
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * An abstract implementation of a Metapath atomic item containing an integer
+ * data value.
+ */
public abstract class AbstractIntegerItem
extends AbstractDecimalItem
implements IIntegerItem {
@@ -55,6 +61,6 @@ public int hashCode() {
@Override
public boolean equals(Object obj) {
return this == obj
- || (obj instanceof IIntegerItem && compareTo((IIntegerItem) obj) == 0);
+ || obj instanceof IIntegerItem && compareTo((IIntegerItem) obj) == 0;
}
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractStringItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/AbstractStringItem.java
similarity index 73%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractStringItem.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/AbstractStringItem.java
index 343c829c2..a4e61b21d 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractStringItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/AbstractStringItem.java
@@ -3,21 +3,35 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
import gov.nist.secauto.metaschema.core.metapath.impl.AbstractStringMapKey;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.AbstractAnyAtomicItem;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IStringItem;
import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey;
import java.util.regex.Pattern;
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * A common base class for all items derived from {@link IStringItem}.
+ */
public abstract class AbstractStringItem
extends AbstractAnyAtomicItem
implements IStringItem {
private static final String WHITESPACE_SEGMENT = "[ \t\r\n]";
+ /**
+ * Pattern to match one or more whitespace characters at the end of a string.
+ */
private static final Pattern TRIM_END = Pattern.compile(WHITESPACE_SEGMENT + "++$");
+ /**
+ * Pattern to match one or more whitespace characters at the start of a string.
+ */
private static final Pattern TRIM_START = Pattern.compile("^" + WHITESPACE_SEGMENT + "+");
+ /**
+ * Pattern to match two or more consecutive whitespace characters.
+ */
private static final Pattern TRIM_MIDDLE = Pattern.compile(WHITESPACE_SEGMENT + "{2,}");
/**
@@ -49,7 +63,7 @@ public int hashCode() {
@Override
public boolean equals(Object obj) {
return this == obj
- || (obj instanceof IStringItem && compareTo((IStringItem) obj) == 0);
+ || obj instanceof IStringItem && compareTo((IStringItem) obj) == 0;
}
private final class MapKey
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractTemporalItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/AbstractTemporalItem.java
similarity index 81%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractTemporalItem.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/AbstractTemporalItem.java
index 893e10ce2..108d927be 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractTemporalItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/AbstractTemporalItem.java
@@ -3,14 +3,16 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.AbstractAnyAtomicItem;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.ITemporalItem;
import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey;
import edu.umd.cs.findbugs.annotations.NonNull;
/**
- * A base class for temporal items.
+ * A base class for all items derived from {@link ITemporalItem}.
*
* @param
* the Java type of the wrapped value
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractUriItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/AbstractUriItem.java
similarity index 73%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractUriItem.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/AbstractUriItem.java
index d65829b7b..3f8c49d2c 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractUriItem.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/AbstractUriItem.java
@@ -3,15 +3,21 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
import gov.nist.secauto.metaschema.core.metapath.impl.AbstractStringMapKey;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.AbstractAnyAtomicItem;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyUriItem;
import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey;
import java.net.URI;
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * An abstract implementation of a Metapath atomic item containing a URI data
+ * value.
+ */
public abstract class AbstractUriItem
extends AbstractAnyAtomicItem
implements IAnyUriItem {
@@ -46,7 +52,7 @@ public int hashCode() {
@Override
public boolean equals(Object obj) {
return this == obj
- || (obj instanceof IAnyUriItem && compareTo((IAnyUriItem) obj) == 0);
+ || obj instanceof IAnyUriItem && compareTo((IAnyUriItem) obj) == 0;
}
private final class MapKey
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AnyUriItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/AnyUriItemImpl.java
similarity index 62%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AnyUriItemImpl.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/AnyUriItemImpl.java
index aada02c99..7df2600cb 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AnyUriItemImpl.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/AnyUriItemImpl.java
@@ -3,7 +3,7 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
import gov.nist.secauto.metaschema.core.datatype.adapter.UriAdapter;
@@ -12,9 +12,18 @@
import edu.umd.cs.findbugs.annotations.NonNull;
-class AnyUriItemImpl
+/**
+ * An implementation of a Metapath atomic item containing a URI data value.
+ */
+public class AnyUriItemImpl
extends AbstractUriItem {
+ /**
+ * Construct a new item with the provided {@code value}.
+ *
+ * @param value
+ * the value to wrap
+ */
public AnyUriItemImpl(@NonNull URI value) {
super(value);
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/Base64BinaryItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/Base64BinaryItemImpl.java
similarity index 66%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/Base64BinaryItemImpl.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/Base64BinaryItemImpl.java
index e742a4340..4ec1450b6 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/Base64BinaryItemImpl.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/Base64BinaryItemImpl.java
@@ -3,20 +3,32 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
import gov.nist.secauto.metaschema.core.datatype.adapter.Base64Adapter;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.AbstractAnyAtomicItem;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IBase64BinaryItem;
import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey;
import java.nio.ByteBuffer;
import edu.umd.cs.findbugs.annotations.NonNull;
-class Base64BinaryItemImpl
+/**
+ * An implementation of a Metapath atomic item containing a Base64 encoded data
+ * value.
+ */
+public class Base64BinaryItemImpl
extends AbstractAnyAtomicItem
implements IBase64BinaryItem {
+ /**
+ * Construct a new item with the provided {@code value}.
+ *
+ * @param value
+ * the value to wrap
+ */
public Base64BinaryItemImpl(@NonNull ByteBuffer value) {
super(value);
}
@@ -45,7 +57,7 @@ public int hashCode() {
@Override
public boolean equals(Object obj) {
return this == obj
- || (obj instanceof IBase64BinaryItem && compareTo((IBase64BinaryItem) obj) == 0);
+ || obj instanceof IBase64BinaryItem && compareTo((IBase64BinaryItem) obj) == 0;
}
private final class MapKey implements IMapKey {
@@ -62,8 +74,8 @@ public int hashCode() {
@Override
public boolean equals(Object obj) {
return this == obj ||
- (obj instanceof MapKey
- && getKey().equals(((MapKey) obj).getKey()));
+ obj instanceof MapKey
+ && getKey().equals(((MapKey) obj).getKey());
}
}
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/BooleanItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/BooleanItemImpl.java
similarity index 66%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/BooleanItemImpl.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/BooleanItemImpl.java
index 2c74b9043..09522bc68 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/BooleanItemImpl.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/BooleanItemImpl.java
@@ -3,15 +3,23 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
import gov.nist.secauto.metaschema.core.datatype.IDataTypeAdapter;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.AbstractAtomicItemBase;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IBooleanItem;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IStringItem;
import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey;
import edu.umd.cs.findbugs.annotations.NonNull;
-class BooleanItemImpl implements IBooleanItem {
+/**
+ * An implementation of a Metapath atomic item with a boolean value.
+ */
+public class BooleanItemImpl
+ extends AbstractAtomicItemBase
+ implements IBooleanItem {
@NonNull
private static final String TRUE_STRING = "true";
@NonNull
@@ -23,8 +31,14 @@ class BooleanItemImpl implements IBooleanItem {
private final boolean booleanValue;
- BooleanItemImpl(boolean booleanValue) {
- this.booleanValue = booleanValue;
+ /**
+ * Construct a new item with the provided {@code value}.
+ *
+ * @param value
+ * the value to wrap
+ */
+ public BooleanItemImpl(boolean value) {
+ this.booleanValue = value;
}
@Override
@@ -48,7 +62,7 @@ public IStringItem asStringItem() {
}
@Override
- public IDataTypeAdapter> getJavaTypeAdapter() {
+ public IDataTypeAdapter getJavaTypeAdapter() {
return MetaschemaDataTypeProvider.BOOLEAN;
}
@@ -71,7 +85,7 @@ public int hashCode() {
@Override
public boolean equals(Object obj) {
return this == obj
- || (obj instanceof IBooleanItem && compareTo((IBooleanItem) obj) == 0);
+ || obj instanceof IBooleanItem && compareTo((IBooleanItem) obj) == 0;
}
private final class MapKey implements IMapKey {
@@ -88,8 +102,8 @@ public int hashCode() {
@Override
public boolean equals(Object obj) {
return this == obj ||
- (obj instanceof MapKey
- && getKey().equals(((MapKey) obj).getKey()));
+ obj instanceof MapKey
+ && getKey().equals(((MapKey) obj).getKey());
}
}
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/DateTimeWithTimeZoneItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/DateTimeWithTimeZoneItemImpl.java
similarity index 65%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/DateTimeWithTimeZoneItemImpl.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/DateTimeWithTimeZoneItemImpl.java
index 1dd0e4efa..af12a8eae 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/DateTimeWithTimeZoneItemImpl.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/DateTimeWithTimeZoneItemImpl.java
@@ -3,7 +3,7 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
import gov.nist.secauto.metaschema.core.datatype.adapter.DateTimeWithTZAdapter;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
@@ -12,9 +12,19 @@
import edu.umd.cs.findbugs.annotations.NonNull;
-class DateTimeWithTimeZoneItemImpl
+/**
+ * An implementation of a Metapath atomic item containing a date/time data value
+ * that has a required timezone.
+ */
+public class DateTimeWithTimeZoneItemImpl
extends AbstractDateTimeItem {
+ /**
+ * Construct a new item with the provided {@code value}.
+ *
+ * @param value
+ * the value to wrap
+ */
public DateTimeWithTimeZoneItemImpl(@NonNull ZonedDateTime value) {
super(value);
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/DateTimeWithoutTimeZoneItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/DateTimeWithoutTimeZoneItemImpl.java
new file mode 100644
index 000000000..4885c1e31
--- /dev/null
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/DateTimeWithoutTimeZoneItemImpl.java
@@ -0,0 +1,47 @@
+/*
+ * SPDX-FileCopyrightText: none
+ * SPDX-License-Identifier: CC0-1.0
+ */
+
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
+
+import gov.nist.secauto.metaschema.core.datatype.adapter.DateTimeAdapter;
+import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
+import gov.nist.secauto.metaschema.core.datatype.object.AmbiguousDateTime;
+
+import java.time.ZonedDateTime;
+
+import edu.umd.cs.findbugs.annotations.NonNull;
+
+/**
+ * An implementation of a Metapath atomic item containing a date/time data value
+ * that may not have an explicit timezone.
+ *
+ * For example, when parsing dates from data sources that don't specify timezone
+ * information, such as "2024-01-01" as compared to "2024-01-01Z" or
+ * "2024-01-01+05:00".
+ */
+public class DateTimeWithoutTimeZoneItemImpl
+ extends AbstractDateTimeItem {
+
+ /**
+ * Construct a new item with the provided {@code value}.
+ *
+ * @param value
+ * the value to wrap
+ */
+ public DateTimeWithoutTimeZoneItemImpl(@NonNull AmbiguousDateTime value) {
+ super(value);
+ }
+
+ @Override
+ public ZonedDateTime asZonedDateTime() {
+ return getValue().getValue();
+ }
+
+ @Override
+ public DateTimeAdapter getJavaTypeAdapter() {
+ return MetaschemaDataTypeProvider.DATE_TIME;
+ }
+
+}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/DateWithTimeZoneItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/DateWithTimeZoneItemImpl.java
similarity index 65%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/DateWithTimeZoneItemImpl.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/DateWithTimeZoneItemImpl.java
index 810aa6066..59de345b8 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/DateWithTimeZoneItemImpl.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/DateWithTimeZoneItemImpl.java
@@ -3,7 +3,7 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
import gov.nist.secauto.metaschema.core.datatype.adapter.DateWithTZAdapter;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
@@ -12,9 +12,19 @@
import edu.umd.cs.findbugs.annotations.NonNull;
-class DateWithTimeZoneItemImpl
+/**
+ * An implementation of a Metapath atomic item containing a date data value that
+ * has a required timezone.
+ */
+public class DateWithTimeZoneItemImpl
extends AbstractDateItem {
+ /**
+ * Construct a new item with the provided {@code value}.
+ *
+ * @param value
+ * the value to wrap
+ */
public DateWithTimeZoneItemImpl(@NonNull ZonedDateTime value) {
super(value);
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/DateWithoutTimeZoneItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/DateWithoutTimeZoneItemImpl.java
new file mode 100644
index 000000000..86f79a4c0
--- /dev/null
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/DateWithoutTimeZoneItemImpl.java
@@ -0,0 +1,43 @@
+/*
+ * SPDX-FileCopyrightText: none
+ * SPDX-License-Identifier: CC0-1.0
+ */
+
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
+
+import gov.nist.secauto.metaschema.core.datatype.adapter.DateAdapter;
+import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
+import gov.nist.secauto.metaschema.core.datatype.object.AmbiguousDate;
+
+import java.time.ZonedDateTime;
+
+import edu.umd.cs.findbugs.annotations.NonNull;
+
+/**
+ * An implementation of a Metapath atomic item containing a date data value that
+ * may not have an explicit timezone.
+ */
+public class DateWithoutTimeZoneItemImpl
+ extends AbstractDateItem {
+
+ /**
+ * Construct a new item with the provided {@code value}.
+ *
+ * @param value
+ * the value to wrap
+ */
+ public DateWithoutTimeZoneItemImpl(@NonNull AmbiguousDate value) {
+ super(value);
+ }
+
+ @Override
+ public ZonedDateTime asZonedDateTime() {
+ return getValue().getValue();
+ }
+
+ @Override
+ public DateAdapter getJavaTypeAdapter() {
+ return MetaschemaDataTypeProvider.DATE;
+ }
+
+}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/DayTimeDurationItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/DayTimeDurationItemImpl.java
similarity index 65%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/DayTimeDurationItemImpl.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/DayTimeDurationItemImpl.java
index fdda3e12d..40dfa04af 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/DayTimeDurationItemImpl.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/DayTimeDurationItemImpl.java
@@ -3,20 +3,32 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
import gov.nist.secauto.metaschema.core.datatype.adapter.DayTimeAdapter;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.AbstractAnyAtomicItem;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IDayTimeDurationItem;
import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey;
import java.time.Duration;
import edu.umd.cs.findbugs.annotations.NonNull;
-class DayTimeDurationItemImpl
+/**
+ * An implementation of a Metapath atomic item containing a duration data value
+ * in days, hours, and seconds.
+ */
+public class DayTimeDurationItemImpl
extends AbstractAnyAtomicItem
implements IDayTimeDurationItem {
+ /**
+ * Construct a new item with the provided {@code value}.
+ *
+ * @param value
+ * the value to wrap
+ */
public DayTimeDurationItemImpl(@NonNull Duration value) {
super(value);
}
@@ -45,7 +57,7 @@ public int hashCode() {
@Override
public boolean equals(Object obj) {
return this == obj
- || (obj instanceof IDayTimeDurationItem && compareTo((IDayTimeDurationItem) obj) == 0);
+ || obj instanceof IDayTimeDurationItem && compareTo((IDayTimeDurationItem) obj) == 0;
}
private final class MapKey implements IMapKey {
@@ -62,8 +74,8 @@ public int hashCode() {
@Override
public boolean equals(Object obj) {
return this == obj ||
- (obj instanceof MapKey
- && getKey().equals(((MapKey) obj).getKey()));
+ obj instanceof MapKey
+ && getKey().equals(((MapKey) obj).getKey());
}
}
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/DecimalItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/DecimalItemImpl.java
similarity index 57%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/DecimalItemImpl.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/DecimalItemImpl.java
index 9157b4a58..d7bde671d 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/DecimalItemImpl.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/DecimalItemImpl.java
@@ -3,10 +3,11 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
import gov.nist.secauto.metaschema.core.datatype.adapter.DecimalAdapter;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IDecimalItem;
import java.math.BigDecimal;
import java.math.BigInteger;
@@ -14,8 +15,34 @@
import edu.umd.cs.findbugs.annotations.NonNull;
-class DecimalItemImpl
+/**
+ * An implementation of a Metapath atomic item containing a decimal data value.
+ */
+public class DecimalItemImpl
extends AbstractDecimalItem {
+ @NonNull
+ private static final BigDecimal BOOLEAN_TRUE = new BigDecimal("1.0");
+ @NonNull
+ private static final BigDecimal BOOLEAN_FALSE = new BigDecimal("0.0");
+
+ /**
+ * Get the equivalent decimal value for the provided boolean value.
+ *
+ * @param value
+ * the boolean value
+ * @return the equivalent decimal value
+ */
+ @NonNull
+ public static BigDecimal toBigDecimal(boolean value) {
+ return value ? BOOLEAN_TRUE : BOOLEAN_FALSE;
+ }
+
+ /**
+ * Construct a new item with the provided {@code value}.
+ *
+ * @param value
+ * the value to wrap
+ */
public DecimalItemImpl(@NonNull BigDecimal value) {
super(value);
}
@@ -53,6 +80,6 @@ public int hashCode() {
@Override
public boolean equals(Object obj) {
return this == obj
- || (obj instanceof IDecimalItem && compareTo((IDecimalItem) obj) == 0);
+ || obj instanceof IDecimalItem && compareTo((IDecimalItem) obj) == 0;
}
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/EmailAddressItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/EmailAddressItemImpl.java
similarity index 57%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/EmailAddressItemImpl.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/EmailAddressItemImpl.java
index ca284a374..964ffcdfe 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/EmailAddressItemImpl.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/EmailAddressItemImpl.java
@@ -3,17 +3,28 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
import gov.nist.secauto.metaschema.core.datatype.adapter.EmailAddressAdapter;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IEmailAddressItem;
import edu.umd.cs.findbugs.annotations.NonNull;
-class EmailAddressItemImpl
+/**
+ * An implementation of a Metapath atomic item containing an email address data
+ * value.
+ */
+public class EmailAddressItemImpl
extends AbstractStringItem
implements IEmailAddressItem {
+ /**
+ * Construct a new item with the provided {@code value}.
+ *
+ * @param value
+ * the value to wrap
+ */
public EmailAddressItemImpl(@NonNull String value) {
super(value);
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/HostnameItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/HostnameItemImpl.java
similarity index 57%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/HostnameItemImpl.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/HostnameItemImpl.java
index 3176da092..8aa51f65e 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/HostnameItemImpl.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/HostnameItemImpl.java
@@ -3,17 +3,27 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
import gov.nist.secauto.metaschema.core.datatype.adapter.HostnameAdapter;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IHostnameItem;
import edu.umd.cs.findbugs.annotations.NonNull;
-class HostnameItemImpl
+/**
+ * An implementation of a Metapath atomic item containing a hostname data value.
+ */
+public class HostnameItemImpl
extends AbstractStringItem
implements IHostnameItem {
+ /**
+ * Construct a new item with the provided {@code value}.
+ *
+ * @param value
+ * the value to wrap
+ */
public HostnameItemImpl(@NonNull String value) {
super(value);
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IPv4AddressItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/IPv4AddressItemImpl.java
similarity index 58%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IPv4AddressItemImpl.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/IPv4AddressItemImpl.java
index 0eb50a346..a650364e6 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IPv4AddressItemImpl.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/IPv4AddressItemImpl.java
@@ -3,18 +3,30 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
import gov.nist.secauto.metaschema.core.datatype.adapter.IPv4AddressAdapter;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.AbstractUntypedAtomicItem;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IIPv4AddressItem;
import edu.umd.cs.findbugs.annotations.NonNull;
import inet.ipaddr.ipv4.IPv4Address;
-class IPv4AddressItemImpl
+/**
+ * An implementation of a Metapath atomic item containing an IPv4 address data
+ * value.
+ */
+public class IPv4AddressItemImpl
extends AbstractUntypedAtomicItem
implements IIPv4AddressItem {
+ /**
+ * Construct a new item with the provided {@code value}.
+ *
+ * @param value
+ * the value to wrap
+ */
public IPv4AddressItemImpl(@NonNull IPv4Address value) {
super(value);
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IPv6AddressItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/IPv6AddressItemImpl.java
similarity index 58%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IPv6AddressItemImpl.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/IPv6AddressItemImpl.java
index 42c03543a..e72eb917e 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IPv6AddressItemImpl.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/IPv6AddressItemImpl.java
@@ -3,18 +3,30 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
import gov.nist.secauto.metaschema.core.datatype.adapter.IPv6AddressAdapter;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.AbstractUntypedAtomicItem;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IIPv6AddressItem;
import edu.umd.cs.findbugs.annotations.NonNull;
import inet.ipaddr.ipv6.IPv6Address;
-class IPv6AddressItemImpl
+/**
+ * An implementation of a Metapath atomic item containing an IPv6 address data
+ * value.
+ */
+public class IPv6AddressItemImpl
extends AbstractUntypedAtomicItem
implements IIPv6AddressItem {
+ /**
+ * Construct a new item with the provided {@code value}.
+ *
+ * @param value
+ * the value to wrap
+ */
public IPv6AddressItemImpl(@NonNull IPv6Address value) {
super(value);
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IntegerItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/IntegerItemImpl.java
similarity index 56%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IntegerItemImpl.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/IntegerItemImpl.java
index 7ff1f5aff..cc4abe588 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IntegerItemImpl.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/IntegerItemImpl.java
@@ -3,7 +3,7 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
import gov.nist.secauto.metaschema.core.datatype.adapter.IntegerAdapter;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
@@ -12,10 +12,19 @@
import edu.umd.cs.findbugs.annotations.NonNull;
-class IntegerItemImpl
+/**
+ * An implementation of a Metapath atomic item containing an integer data value.
+ */
+public class IntegerItemImpl
extends AbstractIntegerItem {
- protected IntegerItemImpl(@NonNull BigInteger value) {
+ /**
+ * Construct a new item with the provided {@code value}.
+ *
+ * @param value
+ * the value to wrap
+ */
+ public IntegerItemImpl(@NonNull BigInteger value) {
super(value);
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/MarkupLineItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/MarkupLineItemImpl.java
similarity index 58%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/MarkupLineItemImpl.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/MarkupLineItemImpl.java
index 1ef4ffb98..ef6e1e912 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/MarkupLineItemImpl.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/MarkupLineItemImpl.java
@@ -3,18 +3,30 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
import gov.nist.secauto.metaschema.core.datatype.markup.MarkupDataTypeProvider;
import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine;
import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLineAdapter;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.AbstractUntypedAtomicItem;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IMarkupItem;
import edu.umd.cs.findbugs.annotations.NonNull;
-class MarkupLineItemImpl
+/**
+ * An implementation of a Metapath atomic item representing a single line Markup
+ * data value.
+ */
+public class MarkupLineItemImpl
extends AbstractUntypedAtomicItem
implements IMarkupItem {
+ /**
+ * Construct a new item with the provided {@code value}.
+ *
+ * @param value
+ * the value to wrap
+ */
public MarkupLineItemImpl(@NonNull MarkupLine value) {
super(value);
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/MarkupMultiLineItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/MarkupMultiLineItemImpl.java
similarity index 59%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/MarkupMultiLineItemImpl.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/MarkupMultiLineItemImpl.java
index bbd1894ab..167d75ab5 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/MarkupMultiLineItemImpl.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/MarkupMultiLineItemImpl.java
@@ -3,18 +3,30 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
import gov.nist.secauto.metaschema.core.datatype.markup.MarkupDataTypeProvider;
import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline;
import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultilineAdapter;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.AbstractUntypedAtomicItem;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IMarkupItem;
import edu.umd.cs.findbugs.annotations.NonNull;
-class MarkupMultiLineItemImpl
+/**
+ * An implementation of a Metapath atomic item representing a multi-line Markup
+ * data value.
+ */
+public class MarkupMultiLineItemImpl
extends AbstractUntypedAtomicItem
implements IMarkupItem {
+ /**
+ * Construct a new item with the provided {@code value}.
+ *
+ * @param value
+ * the value to wrap
+ */
public MarkupMultiLineItemImpl(@NonNull MarkupMultiline value) {
super(value);
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/NcNameItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/NcNameItemImpl.java
similarity index 59%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/NcNameItemImpl.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/NcNameItemImpl.java
index 1a98b075c..7b0b9a88b 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/NcNameItemImpl.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/NcNameItemImpl.java
@@ -3,18 +3,29 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
import gov.nist.secauto.metaschema.core.datatype.adapter.NcNameAdapter;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.INcNameItem;
import edu.umd.cs.findbugs.annotations.NonNull;
+/**
+ * An implementation of a Metapath atomic item containing a non-colonized name
+ * data value.
+ */
@Deprecated(forRemoval = true, since = "0.7.0")
-class NcNameItemImpl
+public class NcNameItemImpl
extends AbstractStringItem
implements INcNameItem {
+ /**
+ * Construct a new item with the provided {@code value}.
+ *
+ * @param value
+ * the value to wrap
+ */
public NcNameItemImpl(@NonNull String value) {
super(value);
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/NonNegativeIntegerItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/NonNegativeIntegerItemImpl.java
similarity index 53%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/NonNegativeIntegerItemImpl.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/NonNegativeIntegerItemImpl.java
index 9d1e97567..cdb07c15f 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/NonNegativeIntegerItemImpl.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/NonNegativeIntegerItemImpl.java
@@ -3,20 +3,31 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
import gov.nist.secauto.metaschema.core.datatype.adapter.NonNegativeIntegerAdapter;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.INonNegativeIntegerItem;
import java.math.BigInteger;
import edu.umd.cs.findbugs.annotations.NonNull;
-class NonNegativeIntegerItemImpl
+/**
+ * An implementation of a Metapath atomic item containing a non-negative integer
+ * data value.
+ */
+public class NonNegativeIntegerItemImpl
extends AbstractIntegerItem
implements INonNegativeIntegerItem {
- protected NonNegativeIntegerItemImpl(@NonNull BigInteger value) {
+ /**
+ * Construct a new item with the provided {@code value}.
+ *
+ * @param value
+ * the value to wrap
+ */
+ public NonNegativeIntegerItemImpl(@NonNull BigInteger value) {
super(value);
}
@@ -24,4 +35,5 @@ protected NonNegativeIntegerItemImpl(@NonNull BigInteger value) {
public NonNegativeIntegerAdapter getJavaTypeAdapter() {
return MetaschemaDataTypeProvider.NON_NEGATIVE_INTEGER;
}
+
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/PositiveIntegerItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/PositiveIntegerItemImpl.java
similarity index 53%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/PositiveIntegerItemImpl.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/PositiveIntegerItemImpl.java
index 9f20445c7..95cec453a 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/PositiveIntegerItemImpl.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/PositiveIntegerItemImpl.java
@@ -3,20 +3,31 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
import gov.nist.secauto.metaschema.core.datatype.adapter.PositiveIntegerAdapter;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IPositiveIntegerItem;
import java.math.BigInteger;
import edu.umd.cs.findbugs.annotations.NonNull;
-class PositiveIntegerItemImpl
+/**
+ * An implementation of a Metapath atomic item containing a positive integer
+ * data value.
+ */
+public class PositiveIntegerItemImpl
extends AbstractIntegerItem
implements IPositiveIntegerItem {
- protected PositiveIntegerItemImpl(@NonNull BigInteger value) {
+ /**
+ * Construct a new item with the provided {@code value}.
+ *
+ * @param value
+ * the value to wrap
+ */
+ public PositiveIntegerItemImpl(@NonNull BigInteger value) {
super(value);
}
@@ -24,4 +35,5 @@ protected PositiveIntegerItemImpl(@NonNull BigInteger value) {
public PositiveIntegerAdapter getJavaTypeAdapter() {
return MetaschemaDataTypeProvider.POSITIVE_INTEGER;
}
+
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/StringItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/StringItemImpl.java
similarity index 61%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/StringItemImpl.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/StringItemImpl.java
index fea0a27c6..2794093df 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/StringItemImpl.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/StringItemImpl.java
@@ -3,16 +3,25 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
import gov.nist.secauto.metaschema.core.datatype.adapter.StringAdapter;
import edu.umd.cs.findbugs.annotations.NonNull;
-class StringItemImpl
+/**
+ * An implementation of a Metapath atomic item containing a text data value.
+ */
+public class StringItemImpl
extends AbstractStringItem {
+ /**
+ * Construct a new item with the provided {@code value}.
+ *
+ * @param value
+ * the value to wrap
+ */
public StringItemImpl(@NonNull String value) {
super(value);
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/TokenItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/TokenItemImpl.java
similarity index 57%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/TokenItemImpl.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/TokenItemImpl.java
index 185404413..98dd86349 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/TokenItemImpl.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/TokenItemImpl.java
@@ -3,17 +3,28 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
import gov.nist.secauto.metaschema.core.datatype.adapter.TokenAdapter;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.ITokenItem;
import edu.umd.cs.findbugs.annotations.NonNull;
-class TokenItemImpl
+/**
+ * An implementation of a Metapath atomic item containing a text token data
+ * value.
+ */
+public class TokenItemImpl
extends AbstractStringItem
implements ITokenItem {
+ /**
+ * Construct a new item with the provided {@code value}.
+ *
+ * @param value
+ * the value to wrap
+ */
public TokenItemImpl(@NonNull String value) {
super(value);
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/UriReferenceItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/UriReferenceItemImpl.java
similarity index 58%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/UriReferenceItemImpl.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/UriReferenceItemImpl.java
index 2e0b6c1a5..e50775222 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/UriReferenceItemImpl.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/UriReferenceItemImpl.java
@@ -3,19 +3,30 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
import gov.nist.secauto.metaschema.core.datatype.adapter.UriReferenceAdapter;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IUriReferenceItem;
import java.net.URI;
import edu.umd.cs.findbugs.annotations.NonNull;
-class UriReferenceItemImpl
+/**
+ * An implementation of a Metapath atomic item containing a URI reference data
+ * value.
+ */
+public class UriReferenceItemImpl
extends AbstractUriItem
implements IUriReferenceItem {
+ /**
+ * Construct a new item with the provided {@code value}.
+ *
+ * @param value
+ * the value to wrap
+ */
public UriReferenceItemImpl(@NonNull URI value) {
super(value);
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/UuidItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/UuidItemImpl.java
similarity index 68%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/UuidItemImpl.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/UuidItemImpl.java
index 69dbdf8b7..94c914961 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/UuidItemImpl.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/UuidItemImpl.java
@@ -3,10 +3,13 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
import gov.nist.secauto.metaschema.core.datatype.adapter.UuidAdapter;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.AbstractAnyAtomicItem;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IStringItem;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IUuidItem;
import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
@@ -14,10 +17,19 @@
import edu.umd.cs.findbugs.annotations.NonNull;
-class UuidItemImpl
+/**
+ * An implementation of a Metapath atomic item containing a UUID data value.
+ */
+public class UuidItemImpl
extends AbstractAnyAtomicItem
implements IUuidItem {
+ /**
+ * Construct a new item with the provided {@code value}.
+ *
+ * @param value
+ * the value to wrap
+ */
public UuidItemImpl(@NonNull UUID value) {
super(value);
}
@@ -51,7 +63,7 @@ public int hashCode() {
@Override
public boolean equals(Object obj) {
return this == obj
- || (obj instanceof IStringItem && compareTo((IStringItem) obj) == 0);
+ || obj instanceof IStringItem && compareTo((IStringItem) obj) == 0;
}
@Override
@@ -68,14 +80,14 @@ public IUuidItem getKey() {
@Override
public int hashCode() {
- return getKey().hashCode();
+ return getKey().asUuid().hashCode();
}
@Override
public boolean equals(Object obj) {
return this == obj ||
- (obj instanceof MapKey
- && getKey().asUuid().equals(((MapKey) obj).getKey().asUuid()));
+ obj instanceof MapKey
+ && getKey().asUuid().equals(((MapKey) obj).getKey().asUuid());
}
}
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/YearMonthDurationItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/YearMonthDurationItemImpl.java
similarity index 66%
rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/YearMonthDurationItemImpl.java
rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/YearMonthDurationItemImpl.java
index 213acb802..f572a2281 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/YearMonthDurationItemImpl.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/impl/YearMonthDurationItemImpl.java
@@ -3,10 +3,12 @@
* SPDX-License-Identifier: CC0-1.0
*/
-package gov.nist.secauto.metaschema.core.metapath.item.atomic;
+package gov.nist.secauto.metaschema.core.metapath.item.atomic.impl;
import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider;
import gov.nist.secauto.metaschema.core.datatype.adapter.YearMonthAdapter;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.AbstractAnyAtomicItem;
+import gov.nist.secauto.metaschema.core.metapath.item.atomic.IYearMonthDurationItem;
import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey;
import java.time.Period;
@@ -14,10 +16,20 @@
import edu.umd.cs.findbugs.annotations.NonNull;
-class YearMonthDurationItemImpl
+/**
+ * An implementation of a Metapath atomic item containing a duration data value
+ * in years and months.
+ */
+public class YearMonthDurationItemImpl
extends AbstractAnyAtomicItem
implements IYearMonthDurationItem {
+ /**
+ * Construct a new item with the provided {@code value}.
+ *
+ * @param value
+ * the value to wrap
+ */
public YearMonthDurationItemImpl(@NonNull Period value) {
super(value);
}
@@ -46,7 +58,7 @@ public int hashCode() {
@Override
public boolean equals(Object obj) {
return this == obj
- || (obj instanceof IYearMonthDurationItem && compareTo((IYearMonthDurationItem) obj) == 0);
+ || obj instanceof IYearMonthDurationItem && compareTo((IYearMonthDurationItem) obj) == 0;
}
private final class MapKey implements IMapKey {
@@ -63,8 +75,8 @@ public int hashCode() {
@Override
public boolean equals(Object obj) {
return this == obj ||
- (obj instanceof MapKey
- && getKey().equals(((MapKey) obj).getKey()));
+ obj instanceof MapKey
+ && getKey().equals(((MapKey) obj).getKey());
}
}
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/validation/XmlSchemaContentValidator.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/validation/XmlSchemaContentValidator.java
index 7558e2d4b..e94b00a72 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/validation/XmlSchemaContentValidator.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/validation/XmlSchemaContentValidator.java
@@ -37,20 +37,29 @@ public class XmlSchemaContentValidator
extends AbstractContentValidator {
private final Schema schema;
- @SuppressWarnings("null")
+ @SuppressWarnings({ "resource", "PMD.UseTryWithResources" })
@NonNull
- private static Schema toSchema(@NonNull List extends Source> schemaSources) throws SAXException {
+ private static Schema toSchema(@NonNull List extends Source> schemaSources) throws IOException {
SchemaFactory schemafactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
// schemafactory.setResourceResolver(new ClasspathResourceResolver());
- Schema retval;
- if (schemaSources.isEmpty()) {
- retval = schemafactory.newSchema();
- } else {
- retval = schemafactory.newSchema(schemaSources.toArray(new Source[0]));
- }
-
// TODO verify source input streams are closed
- return retval;
+ try {
+ return ObjectUtils.notNull(schemaSources.isEmpty()
+ ? schemafactory.newSchema()
+ : schemafactory.newSchema(schemaSources.toArray(new Source[0])));
+ } catch (SAXException ex) {
+ throw new IOException(ex);
+ } finally {
+ // Close all source input streams
+ for (Source source : schemaSources) {
+ if (source instanceof StreamSource) {
+ StreamSource streamSource = (StreamSource) source;
+ if (streamSource.getInputStream() != null) {
+ streamSource.getInputStream().close();
+ }
+ }
+ }
+ }
}
/**
@@ -58,10 +67,10 @@ private static Schema toSchema(@NonNull List extends Source> schemaSources) th
*
* @param schemaSources
* the XML schemas to use for validation
- * @throws SAXException
+ * @throws IOException
* if an error occurred while parsing the provided XML schemas
*/
- public XmlSchemaContentValidator(@Owning @NonNull List extends Source> schemaSources) throws SAXException {
+ public XmlSchemaContentValidator(@Owning @NonNull List extends Source> schemaSources) throws IOException {
this(toSchema(ObjectUtils.requireNonNull(schemaSources, "schemaSources")));
}
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/ModuleLoader.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/ModuleLoader.java
index 8002f23c8..a9e226555 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/ModuleLoader.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/ModuleLoader.java
@@ -47,21 +47,25 @@ public class ModuleLoader
private final List modulePostProcessors;
/**
- * Construct a new Metaschema loader.
+ * Construct a new Metaschema loader, which applies the provided constraints to
+ * loaded modules.
+ *
+ * @param constraints
+ * a set of Metaschema module constraints to be applied during loading
+ * @return the loader instance configured with the specified constraints
*/
- public ModuleLoader() {
- this(CollectionUtil.emptyList());
+ public static ModuleLoader newInstanceUsingConstraints(@NonNull Collection constraints) {
+ return new ModuleLoader(CollectionUtil.singletonList(new ExternalConstraintsModulePostProcessor(constraints)));
}
/**
- * Construct a new Metaschema loader, which applies the provided constraints to
- * loaded modules.
+ * Construct a new Metaschema loader with no constraints.
*
- * @param constraints
- * a set of Metaschema module constraints
+ * @see #newInstanceUsingConstraints(Collection) for creating an instance with
+ * constraints
*/
- public ModuleLoader(@NonNull Collection constraints) {
- this(CollectionUtil.singletonList(new ExternalConstraintsModulePostProcessor(constraints)));
+ public ModuleLoader() {
+ this(CollectionUtil.emptyList());
}
/**
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/XmlbeansMarkupWriter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/XmlbeansMarkupWriter.java
index 94cf92062..bcbbae206 100644
--- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/XmlbeansMarkupWriter.java
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/XmlbeansMarkupWriter.java
@@ -8,10 +8,10 @@
import com.vladsch.flexmark.parser.ListOptions;
import gov.nist.secauto.metaschema.core.datatype.markup.IMarkupString;
-import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.IMarkupVisitor;
-import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.IMarkupWriter;
-import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.MarkupVisitor;
import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl.AbstractMarkupWriter;
+import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl.IMarkupVisitor;
+import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl.IMarkupWriter;
+import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl.MarkupVisitor;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
import org.apache.xmlbeans.XmlCursor;
diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/package-info.java b/core/src/main/java/gov/nist/secauto/metaschema/core/package-info.java
new file mode 100644
index 000000000..b3733e1a0
--- /dev/null
+++ b/core/src/main/java/gov/nist/secauto/metaschema/core/package-info.java
@@ -0,0 +1,10 @@
+/*
+ * SPDX-FileCopyrightText: none
+ * SPDX-License-Identifier: CC0-1.0
+ */
+
+/**
+ * Core support for handling Metaschema-based models.
+ */
+
+package gov.nist.secauto.metaschema.core;
diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/datatype/adapter/DateAdapterTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/datatype/adapter/DateAdapterTest.java
index 354b989be..aee4a2214 100644
--- a/core/src/test/java/gov/nist/secauto/metaschema/core/datatype/adapter/DateAdapterTest.java
+++ b/core/src/test/java/gov/nist/secauto/metaschema/core/datatype/adapter/DateAdapterTest.java
@@ -5,17 +5,60 @@
package gov.nist.secauto.metaschema.core.datatype.adapter;
+import static org.junit.jupiter.api.Assertions.assertAll;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import gov.nist.secauto.metaschema.core.datatype.object.AmbiguousDate;
+
import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.ValueSource;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.util.stream.Stream;
import edu.umd.cs.findbugs.annotations.NonNull;
class DateAdapterTest {
private static final DateAdapter ADAPTER = new DateAdapter();
+ private static Stream provideValues() {
+ return Stream.of(
+ // Cases without timezone (ambiguous)
+ Arguments.of("2018-01-01", true, ZonedDateTime.of(2018, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)),
+ Arguments.of("2020-01-01", true, ZonedDateTime.of(2020, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)),
+ Arguments.of("2018-01-01", true, ZonedDateTime.of(2018, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)),
+ Arguments.of("2000-02-29", true, ZonedDateTime.of(2000, 2, 29, 0, 0, 0, 0, ZoneOffset.UTC)),
+ Arguments.of("2020-02-29", true, ZonedDateTime.of(2020, 2, 29, 0, 0, 0, 0, ZoneOffset.UTC)),
+ // Cases with explicit timezone
+ Arguments.of("2020-06-23Z", false, ZonedDateTime.of(2020, 6, 23, 0, 0, 0, 0, ZoneOffset.UTC)),
+ Arguments.of("2020-06-23-04:00", false, ZonedDateTime.of(2020, 6, 23, 0, 0, 0, 0, ZoneOffset.of("-04:00"))));
+ }
+
+ @ParameterizedTest
+ @MethodSource("provideValues")
+ void testSimpleDate(@NonNull String actual, boolean ambiguous, @NonNull ZonedDateTime expected) {
+ AmbiguousDate date = ADAPTER.parse(actual);
+ assertAll(
+ () -> assertEquals(ambiguous, !date.hasTimeZone()),
+ () -> assertEquals(expected, date.getValue()));
+ }
+
+ private static Stream provideInvalidValues() {
+ return Stream.of(
+ // Cases with invalid date values
+ Arguments.of("2100-02-29"),
+ Arguments.of("2023-02-30Z"),
+ Arguments.of("2023-06-31-04:00"));
+ }
+
@ParameterizedTest
- @ValueSource(strings = { "2018-01-01", "2020-06-23Z", "2020-06-23-04:00", "2020-06-23", "2020-01-01" })
- void testSimpleDate(@NonNull String date) {
- ADAPTER.parse(date);
+ @MethodSource("provideInvalidValues")
+ void testInvalidDates(@NonNull String actual) {
+ assertThrows(IllegalArgumentException.class, () -> {
+ ADAPTER.parse(actual);
+ });
}
}
diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/datatype/adapter/DateTimeAdapterTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/datatype/adapter/DateTimeAdapterTest.java
index a98c5a93a..5e083d4bc 100644
--- a/core/src/test/java/gov/nist/secauto/metaschema/core/datatype/adapter/DateTimeAdapterTest.java
+++ b/core/src/test/java/gov/nist/secauto/metaschema/core/datatype/adapter/DateTimeAdapterTest.java
@@ -5,27 +5,101 @@
package gov.nist.secauto.metaschema.core.datatype.adapter;
-import gov.nist.secauto.metaschema.core.util.ObjectUtils;
+import static org.junit.jupiter.api.Assertions.assertAll;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import gov.nist.secauto.metaschema.core.datatype.object.AmbiguousDateTime;
import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.ValueSource;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Stream;
+
+import edu.umd.cs.findbugs.annotations.NonNull;
class DateTimeAdapterTest {
+ private static final DateTimeAdapter ADAPTER = new DateTimeAdapter();
- @ParameterizedTest
- @ValueSource(strings = {
- "2018-01-01T00:00:00",
- "2019-09-28T23:20:50.52Z",
- "2019-09-28T23:20:50.0Z",
- "2019-09-28T23:20:50.5200",
- "2019-12-02T16:39:57-08:00",
- "2019-12-02T16:39:57.100-08:00",
- "2019-12-02T16:39:57",
- "2019-12-31T23:59:59Z",
- "2019-12-31T23:59:59"
- })
- void testSimpleDate(String date) {
- new DateTimeAdapter().parse(ObjectUtils.requireNonNull(date));
+ /**
+ * Provides test cases for date-time parsing.
+ *
+ * Each argument contains:
+ *
+ * input string to parse
+ * boolean indicating if the datetime is ambiguous (no timezone)
+ * expected ZonedDateTime result
+ *
+ *
+ * @return Stream of test cases
+ */
+ private static Stream provideValues() {
+ return Stream.of(
+ // Cases without timezone (ambiguous)
+ Arguments.of(
+ "2018-01-01T00:00:00",
+ true,
+ ZonedDateTime.of(2018, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)),
+ Arguments.of(
+ "2019-09-28T23:20:50.5200",
+ true,
+ ZonedDateTime.of(2019, 9, 28, 23, 20, 50, toNanos(0.5200), ZoneOffset.UTC)),
+ Arguments.of(
+ "2019-12-02T16:39:57",
+ true,
+ ZonedDateTime.of(2019, 12, 2, 16, 39, 57, 0, ZoneOffset.UTC)),
+ Arguments.of(
+ "2019-12-31T23:59:59",
+ true,
+ ZonedDateTime.of(2019, 12, 31, 23, 59, 59, 0, ZoneOffset.UTC)),
+ // Cases with explicit timezone
+ Arguments.of(
+ "2019-09-28T23:20:50.52Z",
+ false,
+ ZonedDateTime.of(2019, 9, 28, 23, 20, 50, toNanos(0.52), ZoneOffset.UTC)),
+ Arguments.of(
+ "2019-09-28T23:20:50.0Z",
+ false,
+ ZonedDateTime.of(2019, 9, 28, 23, 20, 50, 0, ZoneOffset.UTC)),
+ Arguments.of(
+ "2019-12-02T16:39:57-08:00",
+ false,
+ ZonedDateTime.of(2019, 12, 2, 16, 39, 57, 0, ZoneOffset.of("-08:00"))),
+ Arguments.of(
+ "2019-12-02T16:39:57.100-08:00",
+ false,
+ ZonedDateTime.of(2019, 12, 2, 16, 39, 57, toNanos(0.100), ZoneOffset.of("-08:00"))),
+ Arguments.of(
+ "2019-12-31T23:59:59Z",
+ false,
+ ZonedDateTime.of(2019, 12, 31, 23, 59, 59, 0, ZoneOffset.UTC)));
}
+ /**
+ * Converts a fractional second to nanoseconds.
+ *
+ * @param fraction
+ * the fractional part of a second (0.0 to 0.999...)
+ * @return the equivalent nanoseconds
+ * @throws IllegalArgumentException
+ * if fraction is negative or >= 1
+ */
+ private static int toNanos(double fraction) {
+ if (fraction < 0.0 || fraction >= 1.0) {
+ throw new IllegalArgumentException(String.format("Fraction '%.3f' must be between 0.0 and 0.999...", fraction));
+ }
+ return (int) Math.round(TimeUnit.SECONDS.toNanos(1) * fraction);
+ }
+
+ @ParameterizedTest
+ @MethodSource("provideValues")
+ void testSimpleDateTime(@NonNull String actual, boolean ambiguous, @NonNull ZonedDateTime expected) {
+ AmbiguousDateTime date = ADAPTER.parse(actual);
+ assertAll(
+ () -> assertEquals(ambiguous, !date.hasTimeZone()),
+ () -> assertEquals(expected, date.getValue()));
+ }
}
diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/datatype/markup/CommonmarkConformanceTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/datatype/markup/CommonmarkConformanceTest.java
index 1de4a8059..a1ce8a251 100644
--- a/core/src/test/java/gov/nist/secauto/metaschema/core/datatype/markup/CommonmarkConformanceTest.java
+++ b/core/src/test/java/gov/nist/secauto/metaschema/core/datatype/markup/CommonmarkConformanceTest.java
@@ -19,7 +19,6 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import gov.nist.secauto.metaschema.core.MetaschemaConstants;
-import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.XmlMarkupParser;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
import org.codehaus.stax2.XMLStreamWriter2;
diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/datatype/markup/MarkupStringTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/datatype/markup/MarkupStringTest.java
index 31dce6abc..93529c84b 100644
--- a/core/src/test/java/gov/nist/secauto/metaschema/core/datatype/markup/MarkupStringTest.java
+++ b/core/src/test/java/gov/nist/secauto/metaschema/core/datatype/markup/MarkupStringTest.java
@@ -17,8 +17,8 @@
import com.vladsch.flexmark.util.ast.Document;
import com.vladsch.flexmark.util.ast.Node;
-import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.AstCollectingVisitor;
import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.InsertAnchorExtension.InsertAnchorNode;
+import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl.AstCollectingVisitor;
import gov.nist.secauto.metaschema.core.util.CollectionUtil;
import org.apache.logging.log4j.LogManager;
diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/MarkupParserTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/MarkupParserTest.java
index 41d1bbfe3..e8d998f97 100644
--- a/core/src/test/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/MarkupParserTest.java
+++ b/core/src/test/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/MarkupParserTest.java
@@ -6,10 +6,13 @@
package gov.nist.secauto.metaschema.core.datatype.markup.flexmark;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import com.ctc.wstx.stax.WstxInputFactory;
import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline;
+import gov.nist.secauto.metaschema.core.datatype.markup.XmlMarkupParser;
+import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl.AstCollectingVisitor;
import gov.nist.secauto.metaschema.core.model.util.XmlEventUtil;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
@@ -39,7 +42,7 @@ void test() throws XMLStreamException {
.append("\n")
.append(" some text
\n")
.append(" text
\n")
- .append(" some text .
\n")
+ .append(" some text .
\n")
.append(" Example \n")
.append(" text
\n")
.append(" \n")
@@ -48,7 +51,7 @@ void test() throws XMLStreamException {
.append(" \n")
.append(" \n")
.append(" Heading 1 \n")
- .append(" data1 \n")
+ .append(" data1 \n")
.append("
\n")
.append(" Some more text
\n")
.append(" \n")
@@ -64,11 +67,18 @@ void test() throws XMLStreamException {
assertDoesNotThrow(() -> {
MarkupMultiline markupString = XmlMarkupParser.instance().parseMarkupMultiline(reader, resource);
- AstCollectingVisitor.asString(markupString.getDocument());
- // System.out.println(html);
- // System.out.println(visitor.getAst());
- // System.out.println(markupString.toMarkdown());
-
+ String ast = AstCollectingVisitor.asString(markupString.getDocument());
+
+ // Verify specific elements are properly parsed
+ assertTrue(ast.contains("BulletListItem"), "List items should be present in AST");
+ assertTrue(ast.contains("TableBlock"), "Table should be present in AST");
+
+ // Verify markup conversion
+ String markdown = markupString.toMarkdown();
+ assertTrue(markdown.contains("**list item**"), "Strong text should be converted to markdown");
+ assertTrue(markdown.contains("another *list item*"), "Italic text should be converted to markdown");
+ assertTrue(markdown.contains("{{ insert: param, param-id }}."),
+ "Insert placeholder should be converted to markdown");
});
}
@@ -95,9 +105,14 @@ void emptyParagraphTest() throws XMLStreamException {
assertDoesNotThrow(() -> {
MarkupMultiline ms = XmlMarkupParser.instance().parseMarkupMultiline(reader, resource);
- LOGGER.atDebug().log("AST: {}", AstCollectingVisitor.asString(ms.getDocument()));
- LOGGER.atDebug().log("HTML: {}", ms.toXHtml(""));
- LOGGER.atDebug().log("Markdown: {}", ms.toMarkdown());
+ String ast = AstCollectingVisitor.asString(ms.getDocument());
+ String xhtml = ms.toXHtml("");
+ String markdown = ms.toMarkdown();
+
+ // Verify empty paragraph handling
+ assertTrue(!ast.contains("Paragraph"), "Empty paragraph should be present in AST");
+ assertTrue(xhtml.trim().isEmpty(), "Empty document should produce empty HTML");
+ assertTrue(markdown.trim().isEmpty(), "Empty paragraph should produce empty markdown");
});
}
}
diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnCeilingTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnCeilingTest.java
index 8da0e03a5..c2ea37004 100644
--- a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnCeilingTest.java
+++ b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnCeilingTest.java
@@ -6,6 +6,7 @@
package gov.nist.secauto.metaschema.core.metapath.function.library;
import static gov.nist.secauto.metaschema.core.metapath.TestUtils.decimal;
+import static gov.nist.secauto.metaschema.core.metapath.TestUtils.integer;
import gov.nist.secauto.metaschema.core.metapath.ISequence;
import gov.nist.secauto.metaschema.core.metapath.item.atomic.INumericItem;
@@ -25,8 +26,11 @@ class FnCeilingTest
private static Stream provideValues() {
return Stream.of(
- Arguments.of(decimal("11"), decimal("10.5")),
- Arguments.of(decimal("-10"), decimal("-10.5")));
+ Arguments.of(integer(11), decimal("10.5")),
+ Arguments.of(integer(-10), decimal("-10.5")),
+ Arguments.of(integer(11), decimal("10.1")),
+ Arguments.of(integer(0), decimal("0.0")),
+ Arguments.of(integer(1), decimal("0.999999")));
}
@ParameterizedTest
diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/util/UriUtilsTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/util/UriUtilsTest.java
index 224c6cb50..2c85ba7ac 100644
--- a/core/src/test/java/gov/nist/secauto/metaschema/core/util/UriUtilsTest.java
+++ b/core/src/test/java/gov/nist/secauto/metaschema/core/util/UriUtilsTest.java
@@ -25,7 +25,7 @@
class UriUtilsTest {
private static Stream provideValuesTestToUri() throws MalformedURLException, URISyntaxException {
- String base = Paths.get("").toAbsolutePath().toUri().toURL().toURI().toASCIIString();
+ String base = Paths.get(System.getProperty("user.dir")).toUri().toURL().toURI().toASCIIString();
return Stream.of(
Arguments.of("http://example.org/valid", "http://example.org/valid", true),
Arguments.of("https://example.org/valid", "https://example.org/valid", true),
@@ -46,9 +46,9 @@ private static Stream provideValuesTestToUri() throws MalformedURLExc
@MethodSource("provideValuesTestToUri")
void testToUri(@NonNull String location, @NonNull String expectedLocation, boolean expectedResult)
throws MalformedURLException {
- Path cwd = Paths.get("");
+ Path cwd = Paths.get(System.getProperty("user.dir"));
try {
- URI uri = UriUtils.toUri(location, ObjectUtils.notNull(cwd.toAbsolutePath().toUri())).normalize().toURL().toURI();
+ URI uri = UriUtils.toUri(location, ObjectUtils.notNull(cwd.toUri())).normalize().toURL().toURI();
System.out.println(String.format("%s -> %s", location, uri.toASCIIString()));
assertAll(
() -> assertEquals(uri.toASCIIString(), expectedLocation),
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 a0049ce58..fa7961d2b 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
@@ -10,7 +10,6 @@
import gov.nist.secauto.metaschema.cli.processor.command.AbstractCommandExecutor;
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;
import gov.nist.secauto.metaschema.cli.processor.command.ExtraArgument;
import gov.nist.secauto.metaschema.core.util.AutoCloser;
import gov.nist.secauto.metaschema.core.util.ObjectUtils;
@@ -48,8 +47,8 @@ public abstract class AbstractConvertSubcommand
private static final String COMMAND = "convert";
@NonNull
private static final List EXTRA_ARGUMENTS = ObjectUtils.notNull(List.of(
- new DefaultExtraArgument("source-file-or-URL", true),
- new DefaultExtraArgument("destination-file", false)));
+ ExtraArgument.newInstance("source-file-or-URL", true),
+ ExtraArgument.newInstance("destination-file", false)));
@Override
public String getName() {
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 f854b42d6..723e177d1 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
@@ -11,7 +11,6 @@
import gov.nist.secauto.metaschema.cli.processor.command.AbstractCommandExecutor;
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;
import gov.nist.secauto.metaschema.cli.processor.command.ExtraArgument;
import gov.nist.secauto.metaschema.cli.util.LoggingValidationHandler;
import gov.nist.secauto.metaschema.core.configuration.DefaultConfiguration;
@@ -58,7 +57,7 @@ public abstract class AbstractValidateContentCommand
private static final String COMMAND = "validate";
@NonNull
private static final List EXTRA_ARGUMENTS = ObjectUtils.notNull(List.of(
- new DefaultExtraArgument("file-or-URI-to-validate", true)));
+ ExtraArgument.newInstance("file-or-URI-to-validate", true)));
@NonNull
private static final Option CONSTRAINTS_OPTION = ObjectUtils.notNull(
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 513265be8..815f49411 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
@@ -9,7 +9,6 @@
import gov.nist.secauto.metaschema.cli.processor.ExitCode;
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;
import gov.nist.secauto.metaschema.cli.processor.command.ExtraArgument;
import gov.nist.secauto.metaschema.cli.processor.command.ICommandExecutor;
import gov.nist.secauto.metaschema.core.model.IModule;
@@ -53,8 +52,8 @@ class GenerateDiagramCommand
static {
EXTRA_ARGUMENTS = ObjectUtils.notNull(List.of(
- new DefaultExtraArgument("metaschema-module-file-or-URL", true),
- new DefaultExtraArgument("destination-diagram-file", false)));
+ ExtraArgument.newInstance("metaschema-module-file-or-URL", true),
+ ExtraArgument.newInstance("destination-diagram-file", false)));
}
@Override
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 ba91e4b69..1ec184da8 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
@@ -9,7 +9,6 @@
import gov.nist.secauto.metaschema.cli.processor.ExitCode;
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;
import gov.nist.secauto.metaschema.cli.processor.command.ExtraArgument;
import gov.nist.secauto.metaschema.cli.processor.command.ICommandExecutor;
import gov.nist.secauto.metaschema.core.configuration.DefaultConfiguration;
@@ -36,6 +35,7 @@
import java.util.List;
import edu.umd.cs.findbugs.annotations.NonNull;
+import edu.umd.cs.findbugs.annotations.Nullable;
/**
* This command implementation supports generation of schemas in a variety of
@@ -49,8 +49,8 @@ class GenerateSchemaCommand
private static final String COMMAND = "generate-schema";
@NonNull
private static final List EXTRA_ARGUMENTS = ObjectUtils.notNull(List.of(
- new DefaultExtraArgument("metaschema-module-file-or-URL", true),
- new DefaultExtraArgument("destination-schema-file", false)));
+ ExtraArgument.newInstance("metaschema-module-file-or-URL", true),
+ ExtraArgument.newInstance("destination-schema-file", false)));
private static final Option INLINE_TYPES_OPTION = ObjectUtils.notNull(
Option.builder()
@@ -97,10 +97,6 @@ public ICommandExecutor newExecutor(CallingContext callingContext, CommandLine c
* @throws CommandExecutionException
* if an error occurred while determining the source format
*/
- @SuppressWarnings({
- "PMD.OnlyOneReturn", // readability
- "PMD.CyclomaticComplexity"
- })
protected void executeCommand(
@NonNull CallingContext callingContext,
@NonNull CommandLine cmdLine) throws CommandExecutionException {
@@ -114,6 +110,14 @@ protected void executeCommand(
SchemaFormat asFormat = MetaschemaCommands.getSchemaFormat(cmdLine, MetaschemaCommands.AS_SCHEMA_FORMAT_OPTION);
+ IMutableConfiguration> configuration = createConfiguration(cmdLine, asFormat);
+ generateSchema(extraArgs, destination, asFormat, configuration);
+ }
+
+ @NonNull
+ private static IMutableConfiguration> createConfiguration(
+ @NonNull CommandLine cmdLine,
+ @NonNull SchemaFormat asFormat) {
IMutableConfiguration> configuration = new DefaultConfiguration<>();
if (cmdLine.hasOption(INLINE_TYPES_OPTION)) {
configuration.enableFeature(SchemaGenerationFeature.INLINE_DEFINITIONS);
@@ -123,7 +127,14 @@ protected void executeCommand(
configuration.enableFeature(SchemaGenerationFeature.INLINE_CHOICE_DEFINITIONS);
}
}
+ return configuration;
+ }
+ private static void generateSchema(
+ @NonNull List extraArgs,
+ @Nullable Path destination,
+ @NonNull SchemaFormat asFormat,
+ @NonNull IMutableConfiguration> configuration) throws CommandExecutionException {
IBindingContext bindingContext = MetaschemaCommands.newBindingContextWithDynamicCompilation();
IModule module = MetaschemaCommands.loadModule(
ObjectUtils.requireNonNull(extraArgs.get(0)),
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 0d1a0d79c..dc3155147 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
@@ -19,7 +19,6 @@ public class MetapathCommand
* Constructor for a new Metapath command.
*/
public MetapathCommand() {
- super(true);
addCommandHandler(new ListFunctionsSubcommand());
addCommandHandler(new EvaluateMetapathCommand());
}
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 a8bb95add..c4d70aca3 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
@@ -215,8 +215,10 @@ void testValidateContent() {
.contains("expect-default-non-zero: Expect constraint '. > 0' did not match the data",
"expect-custom-non-zero: No default message, custom error message for expect-custom-non-zero constraint.",
"matches-default-regex-letters-only: Value '1' did not match the pattern",
- "matches-custom-regex-letters-only: No default message, custom error message for matches-custom-regex-letters-only constraint.",
- "cardinality-default-two-minimum: The cardinality '1' is below the required minimum '2' for items matching",
+ "matches-custom-regex-letters-only: No default message, custom error message for" +
+ " matches-custom-regex-letters-only constraint.",
+ "cardinality-default-two-minimum: The cardinality '1' is below the required minimum '2' for items" +
+ " matching",
"index-items-default: Index 'index-items-default' has duplicate key for items",
"index-items-custom: No default message, custom error message for index-item-custom.",
"is-unique-default: Unique constraint violation at paths",
diff --git a/metaschema-testing/src/main/java/gov/nist/secauto/metaschema/model/testing/AbstractTestSuite.java b/metaschema-testing/src/main/java/gov/nist/secauto/metaschema/model/testing/AbstractTestSuite.java
index e1c0e2a3f..f1ded262a 100644
--- a/metaschema-testing/src/main/java/gov/nist/secauto/metaschema/model/testing/AbstractTestSuite.java
+++ b/metaschema-testing/src/main/java/gov/nist/secauto/metaschema/model/testing/AbstractTestSuite.java
@@ -57,6 +57,16 @@
import edu.umd.cs.findbugs.annotations.Nullable;
import nl.talsmasoftware.lazy4j.Lazy;
+/**
+ * This abstract implementation dynamically produces JUnit tests based on a test
+ * suite definition.
+ *
+ * @see #getTestSuiteURI()
+ */
+@SuppressWarnings({
+ "PMD.GodClass",
+ "PMD.CouplingBetweenObjects"
+})
public abstract class AbstractTestSuite {
private static final Logger LOGGER = LogManager.getLogger(AbstractTestSuite.class);
@@ -119,6 +129,9 @@ public abstract class AbstractTestSuite {
/**
* Dynamically generate the unit tests.
*
+ * @param bindingContext
+ * the Module binding context
+ *
* @return the steam of unit tests
*/
@NonNull
@@ -223,6 +236,39 @@ private DynamicContainer generateCollection(
.sequential());
}
+ @NonNull
+ private Path generateSchema(
+ @NonNull IModule module,
+ @NonNull Lazy scenarioGenerationPath) {
+ String schemaExtension;
+ Format requiredContentFormat = getRequiredContentFormat();
+ switch (requiredContentFormat) {
+ case JSON:
+ case YAML:
+ schemaExtension = ".json";
+ break;
+ case XML:
+ schemaExtension = ".xsd";
+ break;
+ default:
+ throw new IllegalStateException();
+ }
+
+ // determine what file to use for the schema
+ Path schemaPath;
+ try {
+ schemaPath = Files.createTempFile(scenarioGenerationPath.get(), "", "-schema" + schemaExtension);
+ } catch (IOException ex) {
+ throw new JUnitException("Unable to create schema temp file", ex);
+ }
+ try {
+ generateSchema(ObjectUtils.notNull(module), ObjectUtils.notNull(schemaPath), getSchemaGeneratorSupplier());
+ } catch (IOException ex) {
+ throw new IllegalStateException(ex);
+ }
+ return ObjectUtils.notNull(schemaPath);
+ }
+
/**
* Generate a schema for the provided module using the provided schema
* generator.
@@ -270,7 +316,7 @@ private DynamicContainer generateScenario(
@NonNull URI collectionUri,
@NonNull Lazy collectionGenerationPath,
@NonNull IBindingContext bindingContext) {
- Lazy scenarioGenerationPath = Lazy.lazy(() -> {
+ Lazy scenarioGenerationPath = ObjectUtils.notNull(Lazy.lazy(() -> {
Path retval;
try {
retval = Files.createTempDirectory(collectionGenerationPath.get(), "scenario-");
@@ -278,15 +324,7 @@ private DynamicContainer generateScenario(
throw new JUnitException("Unable to create scenario temp directory", ex);
}
return retval;
- });
-
- // try {
- // // create the directories the schema will be stored in
- // Files.createDirectories(scenarioGenerationPath);
- // } catch (IOException ex) {
- // throw new JUnitException("Unable to create test directories for path: " +
- // scenarioGenerationPath, ex);
- // }
+ }));
GenerateSchema generateSchema = scenario.getGenerateSchema();
MetaschemaDocument.Metaschema metaschemaDirective = generateSchema.getMetaschema();
@@ -301,35 +339,7 @@ private DynamicContainer generateScenario(
throw new JUnitException("Unable to generate classes for metaschema: " + metaschemaUri, ex);
}
- Lazy lazySchema = Lazy.lazy(() -> {
- String schemaExtension;
- Format requiredContentFormat = getRequiredContentFormat();
- switch (requiredContentFormat) {
- case JSON:
- case YAML:
- schemaExtension = ".json";
- break;
- case XML:
- schemaExtension = ".xsd";
- break;
- default:
- throw new IllegalStateException();
- }
-
- // determine what file to use for the schema
- Path schemaPath;
- try {
- schemaPath = Files.createTempFile(scenarioGenerationPath.get(), "", "-schema" + schemaExtension);
- } catch (IOException ex) {
- throw new JUnitException("Unable to create schema temp file", ex);
- }
- try {
- generateSchema(ObjectUtils.notNull(module), ObjectUtils.notNull(schemaPath), getSchemaGeneratorSupplier());
- } catch (IOException ex) {
- throw new IllegalStateException(ex);
- }
- return schemaPath;
- });
+ Lazy lazySchema = Lazy.lazy(() -> generateSchema(module, scenarioGenerationPath));
Lazy lazyContentValidator = Lazy.lazy(() -> {
Path schemaPath = lazySchema.get();
diff --git a/metaschema-testing/src/main/java/gov/nist/secauto/metaschema/model/testing/xml/xmlbeans/handler/FormatType.java b/metaschema-testing/src/main/java/gov/nist/secauto/metaschema/model/testing/xml/xmlbeans/handler/FormatType.java
index 709c56f73..10cb4bed0 100644
--- a/metaschema-testing/src/main/java/gov/nist/secauto/metaschema/model/testing/xml/xmlbeans/handler/FormatType.java
+++ b/metaschema-testing/src/main/java/gov/nist/secauto/metaschema/model/testing/xml/xmlbeans/handler/FormatType.java
@@ -7,6 +7,9 @@
import gov.nist.secauto.metaschema.databind.io.Format;
+/**
+ * An XMLBeans value handler for parsing and writing {@link Format} values.
+ */
public final class FormatType {
private FormatType() {
// disable
diff --git a/metaschema-testing/src/main/java/gov/nist/secauto/metaschema/model/testing/xml/xmlbeans/handler/GenerationResultType.java b/metaschema-testing/src/main/java/gov/nist/secauto/metaschema/model/testing/xml/xmlbeans/handler/GenerationResultType.java
index 3a4acc8f9..2c1758b50 100644
--- a/metaschema-testing/src/main/java/gov/nist/secauto/metaschema/model/testing/xml/xmlbeans/handler/GenerationResultType.java
+++ b/metaschema-testing/src/main/java/gov/nist/secauto/metaschema/model/testing/xml/xmlbeans/handler/GenerationResultType.java
@@ -5,6 +5,10 @@
package gov.nist.secauto.metaschema.model.testing.xml.xmlbeans.handler;
+/**
+ * An XMLBeans value handler for parsing and writing boolean generation result
+ * type values.
+ */
public final class GenerationResultType {
private GenerationResultType() {
// disable
diff --git a/metaschema-testing/src/main/java/gov/nist/secauto/metaschema/model/testing/xml/xmlbeans/handler/ValidationResultType.java b/metaschema-testing/src/main/java/gov/nist/secauto/metaschema/model/testing/xml/xmlbeans/handler/ValidationResultType.java
index d4bf1cce0..02dc90558 100644
--- a/metaschema-testing/src/main/java/gov/nist/secauto/metaschema/model/testing/xml/xmlbeans/handler/ValidationResultType.java
+++ b/metaschema-testing/src/main/java/gov/nist/secauto/metaschema/model/testing/xml/xmlbeans/handler/ValidationResultType.java
@@ -5,6 +5,11 @@
package gov.nist.secauto.metaschema.model.testing.xml.xmlbeans.handler;
+/**
+ * An XMLBeans value handler for parsing and writing boolean validation result
+ * type values.
+ */
+
public final class ValidationResultType {
private ValidationResultType() {
// disable
diff --git a/pom.xml b/pom.xml
index 0e495dbc1..ac9b6b90b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
dev.metaschema
oss-parent
- 5
+ 6-SNAPSHOT
dev.metaschema.java
@@ -57,7 +57,6 @@
2.0.6.1
2.13.1
20240303
- 5.11.3
2.24.1
2.9.3
5.14.2
@@ -65,9 +64,7 @@
${project.parent.version}
4.0.2
1.2.0
- 7.7.0
12.5
- 4.8.6
4.2.2
3.1.2.RELEASE
7.1.0
@@ -82,13 +79,7 @@
1.22
2.1.0
9.0.1
- 3.11.1
- 2.12.1
- 3.8.1
- 3.2.0
- 3.26.0
- 4.8.6.5
- 3.5.2
+
3.0.0
-Xmx1024m
@@ -437,11 +428,6 @@
compiler
2.26ea0
-
- com.github.spotbugs
- spotbugs-annotations
- ${dependency.spotbugs-annotations.version}
-
org.eclipse.jdt
org.eclipse.jdt.annotation
@@ -452,13 +438,6 @@
caffeine
${dependency.caffeine.version}
-
- org.junit
- junit-bom
- ${dependency.junit5.version}
- pom
- import
-
org.jmock
jmock-junit5
@@ -500,11 +479,6 @@
${dependency.assertj.version}
test
-
- org.apache.maven.plugin-tools
- maven-plugin-annotations
- 3.15.1
-
biz.aQute.bnd
@@ -549,7 +523,6 @@
org.apache.maven.plugins
maven-toolchains-plugin
- ${plugin.maven-toolchains.version}
@@ -642,7 +615,6 @@
org.apache.maven.plugins
maven-jxr-plugin
- 3.6.0
**/module-info.java
@@ -652,7 +624,6 @@
org.apache.maven.plugins
maven-javadoc-plugin
- ${plugin.maven-javadoc.version}
*.xmlbeans:*.xmlbeans.*:*.antlr
false
@@ -679,18 +650,12 @@
com.github.spotbugs
spotbugs-maven-plugin
- ${plugin.spotbugs.version}
spotbugs-exclude.xml
true
spotbugs.sarif
-
- org.apache.maven.plugins
- maven-invoker-plugin
- ${plugin.maven-invoker.version}
-
io.github.git-commit-id
git-commit-id-maven-plugin
@@ -714,7 +679,6 @@
org.apache.maven.plugins
maven-surefire-plugin
- ${plugin.maven-surefire.version}
1.5C
true
@@ -729,19 +693,6 @@
org.apache.maven.plugins
maven-pmd-plugin
- ${plugin.pmd.version}
-
-
- net.sourceforge.pmd
- pmd-core
- ${dependency.pmd.version}
-
-
- net.sourceforge.pmd
- pmd-java
- ${dependency.pmd.version}
-
-
pmd-verify
diff --git a/schemagen/src/test/java/gov/nist/secauto/metaschema/schemagen/AbstractSchemaGeneratorTestSuite.java b/schemagen/src/test/java/gov/nist/secauto/metaschema/schemagen/AbstractSchemaGeneratorTestSuite.java
index 1b082e784..59c6de450 100644
--- a/schemagen/src/test/java/gov/nist/secauto/metaschema/schemagen/AbstractSchemaGeneratorTestSuite.java
+++ b/schemagen/src/test/java/gov/nist/secauto/metaschema/schemagen/AbstractSchemaGeneratorTestSuite.java
@@ -26,7 +26,6 @@
import gov.nist.secauto.metaschema.schemagen.xml.XmlSchemaGenerator;
import org.junit.platform.commons.JUnitException;
-import org.xml.sax.SAXException;
import java.io.IOException;
import java.io.InputStream;
@@ -123,7 +122,7 @@ public abstract class AbstractSchemaGeneratorTestSuite
= new StreamSource(schemaResource.openStream(), schemaResource.toString());
List extends Source> schemaSources = Collections.singletonList(source);
return new XmlSchemaContentValidator(schemaSources);
- } catch (IOException | SAXException ex) {
+ } catch (IOException ex) {
throw new IllegalStateException(ex);
}
};