diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..6d826dcd1 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,9 @@ +# To list all file extensions: +# git ls-files | awk -F . {'print $NF'}|sort -u +# +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto + +# files that are binary +*.png +*.jpg diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ba26e1aa1..f6b59f9af 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,6 +3,18 @@ on: tags: - "v*" workflow_dispatch: + inputs: + release: + description: 'Delpoy release?' + type: boolean + default: false + website: + description: 'Deploy website?' + type: boolean + default: false + pages-branch: + description: 'Pages branch name' + default: nist-pages name: Deploy Tagged Release jobs: deploy-to-nexus: @@ -38,6 +50,7 @@ jobs: # Maven Deploy # ------------------------- - name: Deploy Maven Artifacts + if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && contains('true', github.event.inputs.release)) run: | mvn -B -e -Pgpg -Prelease -Preporting deploy # mvn -Pgpg -Prelease nexus-staging:close -DstagingDescription="closing to release" @@ -46,6 +59,7 @@ jobs: MAVEN_CENTRAL_TOKEN: ${{ secrets.SONATYPE_PASSWORD }} MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} - name: Create release + if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && contains('true', github.event.inputs.release)) uses: softprops/action-gh-release@9d7c94cfd0a1f3ed45544c887983e9fa900f0564 with: draft: true @@ -57,9 +71,14 @@ jobs: # Maven Site # ------------------------- - name: Build Website + if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && contains('true', github.event.inputs.website)) run: | mvn -B -e -Prelease -Preporting install site site:stage - - name: Run Website Deploy Script - run: | - touch target/staging/.nojekyll - bash .github/workflows/deploy.sh --push-only -v -m "Deploying website [ci skip]" + - name: Website Deploy + uses: peaceiris/actions-gh-pages@373f7f263a76c20808c831209c920827a82a2847 + if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && contains('true', github.event.inputs.website)) + with: + personal_token: ${{ secrets.COMMIT_TOKEN }} + publish_dir: ./target/staging + external_repository: ${{ github.repository }} + publish_branch: ${{ (github.event_name == 'workflow_dispatch' && github.event.inputs.pages-branch) || 'nist-pages' }} 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 44a921fdd..36a318b26 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 @@ -66,6 +66,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; public class CLIProcessor { private static final Logger LOGGER = LogManager.getLogger(CLIProcessor.class); @@ -195,7 +196,7 @@ private ExitStatus parseCommand(String... args) { return status; } - protected List getTopLevelCommands() { + protected final List getTopLevelCommands() { List retval = Collections.unmodifiableList(commands); assert retval != null; return retval; @@ -220,7 +221,7 @@ public static void handleQuiet() { protected void showVersion() { @SuppressWarnings("resource") PrintStream out = AnsiConsole.out(); // NOPMD - not owner - getVersionInfos().stream().forEach((info) -> { + getVersionInfos().stream().forEach(info -> { out.println(ansi() .bold().a(info.getName()).boldOff() .a(" ") @@ -253,6 +254,7 @@ public class CallingContext { @NonNull private final List extraArgs; + @SuppressFBWarnings(value = "CT_CONSTRUCTOR_THROW", justification = "Use of final fields") public CallingContext(@NonNull List args) { Map topLevelCommandMap = getTopLevelCommands().stream() .collect(Collectors.toUnmodifiableMap(ICommand::getName, Function.identity())); @@ -263,35 +265,31 @@ public CallingContext(@NonNull List args) { boolean endArgs = false; for (String arg : args) { - if (endArgs) { + if (endArgs || arg.startsWith("-")) { extraArgs.add(arg); + } else if ("--".equals(arg)) { + endArgs = true; } else { - if (arg.startsWith("-")) { + ICommand command; + if (calledCommands.isEmpty()) { + command = topLevelCommandMap.get(arg); + } else { + command = calledCommands.getLast(); + command = command.getSubCommandByName(arg); + } + + if (command == null) { extraArgs.add(arg); - } else if ("--".equals(arg)) { endArgs = true; } else { - ICommand command; - if (calledCommands.isEmpty()) { - command = topLevelCommandMap.get(arg); - } else { - command = calledCommands.getLast(); - command = command.getSubCommandByName(arg); - } - - if (command == null) { - extraArgs.add(arg); - endArgs = true; - } else { - calledCommands.add(command); - } + calledCommands.add(command); } } } if (LOGGER.isDebugEnabled()) { String commandChain = calledCommands.stream() - .map(command -> command.getName()) + .map(ICommand::getName) .collect(Collectors.joining(" -> ")); LOGGER.debug("Processing command chain: {}", commandChain); } @@ -546,7 +544,7 @@ protected String buildHelpCliSyntax() { // output required options getOptionsList().stream() - .filter(option -> option.isRequired()) + .filter(Option::isRequired) .forEach(option -> { builder .append(' ') 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 dc3f72b9a..0416006e3 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 @@ -51,7 +51,7 @@ protected AbstractParentCommand(boolean subCommandRequired) { this.subCommandRequired = subCommandRequired; } - protected void addCommandHandler(ICommand handler) { + protected final void addCommandHandler(ICommand handler) { String commandName = handler.getName(); this.commandToSubcommandHandlerMap.put(commandName, handler); } @@ -87,7 +87,7 @@ protected ExitStatus executeCommand( status = ExitCode.INVALID_COMMAND .exitMessage("Please use one of the following sub-commands: " + getSubCommands().stream() - .map(command -> command.getName()) + .map(ICommand::getName) .collect(Collectors.joining(", "))); } else { status = ExitCode.OK.exit(); 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 index d98b79211..591ed48f1 100644 --- 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 @@ -26,15 +26,19 @@ 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"); diff --git a/cli-processor/src/main/resources/log4j2.xml b/cli-processor/src/main/resources/log4j2.xml index b174b3f80..758bf2a4c 100644 --- a/cli-processor/src/main/resources/log4j2.xml +++ b/cli-processor/src/main/resources/log4j2.xml @@ -2,11 +2,11 @@ - + - + diff --git a/core/metaschema b/core/metaschema index 16919d512..9527c9441 160000 --- a/core/metaschema +++ b/core/metaschema @@ -1 +1 @@ -Subproject commit 16919d512f96110c49fa2edcd3e6ee9a377c0b69 +Subproject commit 9527c9441f02fa8d31bf03b6e16190f6de8554eb diff --git a/core/pom.xml b/core/pom.xml index 6e8baf269..e4fabc367 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -169,9 +169,10 @@ jacoco-maven-plugin - - gov/nist/secauto/metaschema/core/model/xml/xmlbeans/**/* + + gov/nist/secauto/metaschema/core/model/xml/xmlbeans/**/* org/apache/xmlbeans/**/* + gov/nist/secauto/metaschema/core/metapath/antlr/* diff --git a/core/src/main/antlr4/Metapath10.g4 b/core/src/main/antlr4/Metapath10.g4 index 77e81a4b0..0fb07f3ca 100644 --- a/core/src/main/antlr4/Metapath10.g4 +++ b/core/src/main/antlr4/Metapath10.g4 @@ -4,16 +4,13 @@ parser grammar Metapath10; options { tokenVocab=Metapath10Lexer; superClass=Metapath10ParserBase; } -// Metapath extensions -metapath : expr EOF ; - // [1] -// xpath : expr EOF ; +metapath : expr EOF ; // paramlist : param ( COMMA param)* ; // param : DOLLAR eqname typedeclaration? ; // functionbody : enclosedexpr ; // [5] -// enclosedexpr : OC expr? CC ; +enclosedexpr : OC expr? CC ; expr : exprsingle ( COMMA exprsingle)* ; exprsingle : forexpr | letexpr | quantifiedexpr | ifexpr | orexpr ; forexpr : simpleforclause KW_RETURN exprsingle ; @@ -57,14 +54,11 @@ relativepathexpr : stepexpr (( SLASH | SS) stepexpr)* ; stepexpr : postfixexpr | axisstep ; axisstep : (reversestep | forwardstep) predicatelist ; // [40] -// forwardstep : forwardaxis nodetest | abbrevforwardstep ; -forwardstep : forwardaxis nametest | abbrevforwardstep ; +forwardstep : forwardaxis nodetest | abbrevforwardstep ; // forwardaxis : KW_CHILD COLONCOLON | KW_DESCENDANT COLONCOLON | KW_ATTRIBUTE COLONCOLON | KW_SELF COLONCOLON | KW_DESCENDANT_OR_SELF COLONCOLON | KW_FOLLOWING_SIBLING COLONCOLON | KW_FOLLOWING COLONCOLON | KW_NAMESPACE COLONCOLON ; forwardaxis : KW_CHILD COLONCOLON | KW_DESCENDANT COLONCOLON | KW_SELF COLONCOLON | KW_DESCENDANT_OR_SELF COLONCOLON ; -// abbrevforwardstep : AT? nodetest ; -abbrevforwardstep : AT? nametest ; -// reversestep : reverseaxis nodetest | abbrevreversestep ; -reversestep : reverseaxis nametest | abbrevreversestep ; +abbrevforwardstep : AT? nodetest ; +reversestep : reverseaxis nodetest | abbrevreversestep ; // reverseaxis : KW_PARENT COLONCOLON | KW_ANCESTOR COLONCOLON | KW_PRECEDING_SIBLING COLONCOLON | KW_PRECEDING COLONCOLON | KW_ANCESTOR_OR_SELF COLONCOLON ; reverseaxis : KW_PARENT COLONCOLON | KW_ANCESTOR COLONCOLON | KW_ANCESTOR_OR_SELF COLONCOLON ; // [45] @@ -73,19 +67,18 @@ abbrevreversestep : DD ; nodetest : nametest ; nametest : eqname | wildcard ; wildcard : STAR | NCName CS | SC NCName | BracedURILiteral STAR ; -// postfixexpr : primaryexpr (predicate | argumentlist | lookup)* ; -postfixexpr : primaryexpr (predicate)* ; +postfixexpr : primaryexpr (predicate | argumentlist | lookup)* ; // [50] argumentlist : OP (argument ( COMMA argument)*)? CP ; predicatelist : predicate* ; predicate : OB expr CB ; -// lookup : QM keyspecifier ; -// keyspecifier : NCName | IntegerLiteral | parenthesizedexpr | STAR ; +lookup : QM keyspecifier ; +keyspecifier : NCName | IntegerLiteral | parenthesizedexpr | STAR ; // [55] //arrowfunctionspecifier : eqname | varref | parenthesizedexpr ; arrowfunctionspecifier : eqname; // primaryexpr : literal | varref | parenthesizedexpr | contextitemexpr | functioncall | functionitemexpr | mapconstructor | arrayconstructor | unarylookup ; -primaryexpr : literal | varref | parenthesizedexpr | contextitemexpr | functioncall ; +primaryexpr : literal | varref | parenthesizedexpr | contextitemexpr | functioncall | mapconstructor | arrayconstructor | unarylookup; literal : numericliteral | StringLiteral ; numericliteral : IntegerLiteral | DecimalLiteral | DoubleLiteral ; varref : DOLLAR varname ; @@ -101,16 +94,16 @@ argument : exprsingle ; // functionitemexpr : namedfunctionref | inlinefunctionexpr ; // namedfunctionref : eqname POUND IntegerLiteral /* xgc: reserved-function-names */; // inlinefunctionexpr : KW_FUNCTION OP paramlist? CP ( KW_AS sequencetype)? functionbody ; -// mapconstructor : KW_MAP OC (mapconstructorentry ( COMMA mapconstructorentry)*)? CC ; +mapconstructor : KW_MAP OC (mapconstructorentry ( COMMA mapconstructorentry)*)? CC ; // [70] -// mapconstructorentry : mapkeyexpr COLON mapvalueexpr ; -// mapkeyexpr : exprsingle ; -// mapvalueexpr : exprsingle ; -// arrayconstructor : squarearrayconstructor | curlyarrayconstructor ; -// squarearrayconstructor : OB (exprsingle ( COMMA exprsingle)*)? CB ; +mapconstructorentry : mapkeyexpr COLON mapvalueexpr ; +mapkeyexpr : exprsingle ; +mapvalueexpr : exprsingle ; +arrayconstructor : squarearrayconstructor | curlyarrayconstructor ; +squarearrayconstructor : OB (exprsingle ( COMMA exprsingle)*)? CB ; // [75] -// curlyarrayconstructor : KW_ARRAY enclosedexpr ; -// unarylookup : QM keyspecifier ; +curlyarrayconstructor : KW_ARRAY enclosedexpr ; +unarylookup : QM keyspecifier ; // singletype : simpletypename QM? ; // typedeclaration : KW_AS sequencetype ; // sequencetype : KW_EMPTY_SEQUENCE OP CP | itemtype occurrenceindicator? ; @@ -156,7 +149,7 @@ argument : exprsingle ; // Error in the spec. EQName also includes acceptable keywords. -eqname : QName | URIQualifiedName +eqname : NCName | QName | URIQualifiedName | KW_ANCESTOR | KW_ANCESTOR_OR_SELF | KW_AND diff --git a/core/src/main/antlr4/Metapath10Lexer.g4 b/core/src/main/antlr4/Metapath10Lexer.g4 index f95456ef4..21c735e2f 100644 --- a/core/src/main/antlr4/Metapath10Lexer.g4 +++ b/core/src/main/antlr4/Metapath10Lexer.g4 @@ -1,166 +1,180 @@ // This grammar is derived from the XPath 3.1 grammar produced by Ken Domino, et al (https://github.com/antlr/grammars-v4/blob/63359bd91593ece31a384acd507ae860d6cf7ff7/xpath/xpath31/XPath31Lexer.g4). +// This is a faithful implementation of the XPath version 3.1 grammar +// from the spec at https://www.w3.org/TR/2017/REC-xpath-31-20170321/ + +// $antlr-format alignTrailingComments true, columnLimit 150, maxEmptyLinesToKeep 1, reflowComments false, useTab false +// $antlr-format allowShortRulesOnASingleLine true, allowShortBlocksOnASingleLine true, minEmptyLines 0, alignSemicolons ownLine +// $antlr-format alignColons trailing, singleLineOverrulesHangingColon true, alignLexerCommands true, alignLabels true, alignTrailers true + lexer grammar Metapath10Lexer; -AT : '@' ; -BANG : '!' ; -CB : ']' ; -CC : '}' ; -CEQ : ':=' ; -COLON : ':' ; -COLONCOLON : '::' ; -COMMA : ',' ; -CP : ')' ; -CS : ':*' ; -D : '.' ; -DD : '..' ; -DOLLAR : '$' ; -EG : '=>' ; -EQ : '=' ; -GE : '>=' ; -GG : '>>' ; -GT : '>' ; -LE : '<=' ; -LL : '<<' ; -LT : '<' ; -MINUS : '-' ; -NE : '!=' ; -OB : '[' ; -OC : '{' ; -OP : '(' ; -P : '|' ; -PLUS : '+' ; -POUND : '#' ; -PP : '||' ; -QM : '?' ; -SC : '*:' ; -SLASH : '/' ; -SS : '//' ; -STAR : '*' ; +AT : '@'; +BANG : '!'; +CB : ']'; +CC : '}'; +CEQ : ':='; +COLON : ':'; +COLONCOLON : '::'; +COMMA : ','; +CP : ')'; +CS : ':*'; +D : '.'; +DD : '..'; +DOLLAR : '$'; +EG : '=>'; +EQ : '='; +GE : '>='; +GG : '>>'; +GT : '>'; +LE : '<='; +LL : '<<'; +LT : '<'; +MINUS : '-'; +NE : '!='; +OB : '['; +OC : '{'; +OP : '('; +P : '|'; +PLUS : '+'; +POUND : '#'; +PP : '||'; +QM : '?'; +SC : '*:'; +SLASH : '/'; +SS : '//'; +STAR : '*'; // KEYWORDS -KW_ANCESTOR : 'ancestor' ; -KW_ANCESTOR_OR_SELF : 'ancestor-or-self' ; -KW_AND : 'and' ; -KW_ARRAY : 'array' ; -KW_AS : 'as' ; -KW_ATTRIBUTE : 'attribute' ; -KW_CAST : 'cast' ; -KW_CASTABLE : 'castable' ; -KW_CHILD : 'child' ; -KW_COMMENT : 'comment' ; -KW_DESCENDANT : 'descendant' ; -KW_DESCENDANT_OR_SELF : 'descendant-or-self' ; -KW_DIV : 'div' ; -KW_DOCUMENT_NODE : 'document-node' ; -KW_ELEMENT : 'element' ; -KW_ELSE : 'else' ; -KW_EMPTY_SEQUENCE : 'empty-sequence' ; -KW_EQ : 'eq' ; -KW_EVERY : 'every' ; -KW_EXCEPT : 'except' ; -KW_FOLLOWING : 'following' ; -KW_FOLLOWING_SIBLING : 'following-sibling' ; -KW_FOR : 'for' ; -KW_FUNCTION : 'function' ; -KW_GE : 'ge' ; -KW_GT : 'gt' ; -KW_IDIV : 'idiv' ; -KW_IF : 'if' ; -KW_IN : 'in' ; -KW_INSTANCE : 'instance' ; -KW_INTERSECT : 'intersect' ; -KW_IS : 'is' ; -KW_ITEM : 'item' ; -KW_LE : 'le' ; -KW_LET : 'let' ; -KW_LT : 'lt' ; -KW_MAP : 'map' ; -KW_MOD : 'mod' ; -KW_NAMESPACE : 'namespace' ; -KW_NAMESPACE_NODE : 'namespace-node' ; -KW_NE : 'ne' ; -KW_NODE : 'node' ; -KW_OF : 'of' ; -KW_OR : 'or' ; -KW_PARENT : 'parent' ; -KW_PRECEDING : 'preceding' ; -KW_PRECEDING_SIBLING : 'preceding-sibling' ; -KW_PROCESSING_INSTRUCTION : 'processing-instruction' ; -KW_RETURN : 'return' ; -KW_SATISFIES : 'satisfies' ; -KW_SCHEMA_ATTRIBUTE : 'schema-attribute' ; -KW_SCHEMA_ELEMENT : 'schema-element' ; -KW_SELF : 'self' ; -KW_SOME : 'some' ; -KW_TEXT : 'text' ; -KW_THEN : 'then' ; -KW_TO : 'to' ; -KW_TREAT : 'treat' ; -KW_UNION : 'union' ; +KW_ANCESTOR : 'ancestor'; +KW_ANCESTOR_OR_SELF : 'ancestor-or-self'; +KW_AND : 'and'; +KW_ARRAY : 'array'; +KW_AS : 'as'; +KW_ATTRIBUTE : 'attribute'; +KW_CAST : 'cast'; +KW_CASTABLE : 'castable'; +KW_CHILD : 'child'; +KW_COMMENT : 'comment'; +KW_DESCENDANT : 'descendant'; +KW_DESCENDANT_OR_SELF : 'descendant-or-self'; +KW_DIV : 'div'; +KW_DOCUMENT_NODE : 'document-node'; +KW_ELEMENT : 'element'; +KW_ELSE : 'else'; +KW_EMPTY_SEQUENCE : 'empty-sequence'; +KW_EQ : 'eq'; +KW_EVERY : 'every'; +KW_EXCEPT : 'except'; +KW_FOLLOWING : 'following'; +KW_FOLLOWING_SIBLING : 'following-sibling'; +KW_FOR : 'for'; +KW_FUNCTION : 'function'; +KW_GE : 'ge'; +KW_GT : 'gt'; +KW_IDIV : 'idiv'; +KW_IF : 'if'; +KW_IN : 'in'; +KW_INSTANCE : 'instance'; +KW_INTERSECT : 'intersect'; +KW_IS : 'is'; +KW_ITEM : 'item'; +KW_LE : 'le'; +KW_LET : 'let'; +KW_LT : 'lt'; +KW_MAP : 'map'; +KW_MOD : 'mod'; +KW_NAMESPACE : 'namespace'; +KW_NAMESPACE_NODE : 'namespace-node'; +KW_NE : 'ne'; +KW_NODE : 'node'; +KW_OF : 'of'; +KW_OR : 'or'; +KW_PARENT : 'parent'; +KW_PRECEDING : 'preceding'; +KW_PRECEDING_SIBLING : 'preceding-sibling'; +KW_PROCESSING_INSTRUCTION : 'processing-instruction'; +KW_RETURN : 'return'; +KW_SATISFIES : 'satisfies'; +KW_SCHEMA_ATTRIBUTE : 'schema-attribute'; +KW_SCHEMA_ELEMENT : 'schema-element'; +KW_SELF : 'self'; +KW_SOME : 'some'; +KW_TEXT : 'text'; +KW_THEN : 'then'; +KW_TO : 'to'; +KW_TREAT : 'treat'; +KW_UNION : 'union'; // A.2.1. TERMINAL SYMBOLS // This isn't a complete list of tokens in the language. // Keywords and symbols are terminals. -IntegerLiteral : FragDigits ; -DecimalLiteral : '.' FragDigits | FragDigits '.' [0-9]* ; -DoubleLiteral : ('.' FragDigits | FragDigits ('.' [0-9]*)?) [eE] [+-]? FragDigits ; -StringLiteral : '"' (~["] | FragEscapeQuot)* '"' | '\'' (~['] | FragEscapeApos)* '\'' ; -URIQualifiedName : BracedURILiteral NCName ; -BracedURILiteral : 'Q' '{' [^{}]* '}' ; +IntegerLiteral : FragDigits; +DecimalLiteral : '.' FragDigits | FragDigits '.' [0-9]*; +DoubleLiteral : ('.' FragDigits | FragDigits ('.' [0-9]*)?) [eE] [+-]? FragDigits; +StringLiteral : '"' (~["] | FragEscapeQuot)* '"' | '\'' (~['] | FragEscapeApos)* '\''; +URIQualifiedName : BracedURILiteral NCName; +BracedURILiteral : 'Q' '{' [^{}]* '}'; // Error in spec: EscapeQuot and EscapeApos are not terminals! -fragment FragEscapeQuot : '""' ; +fragment FragEscapeQuot : '""'; fragment FragEscapeApos : '\'\''; // Error in spec: Comment isn't really a terminal, but an off-channel object. -Comment : '(:' (Comment | CommentContents)*? ':)' -> skip ; -QName : FragQName ; -NCName : FragmentNCName ; +Comment : '(:' (Comment | CommentContents)*? ':)' -> skip; +NCName : FragmentNCName; +QName : FragQName; // Error in spec: Char is not a terminal! -fragment Char : FragChar ; -fragment FragDigits : [0-9]+ ; -fragment CommentContents : Char ; +fragment Char : FragChar; +fragment FragDigits : [0-9]+; +fragment CommentContents : Char; // https://www.w3.org/TR/REC-xml-names/#NT-QName -fragment FragQName : FragPrefixedName | FragUnprefixedName ; -fragment FragPrefixedName : FragPrefix ':' FragLocalPart ; -fragment FragUnprefixedName : FragLocalPart ; -fragment FragPrefix : FragmentNCName ; -fragment FragLocalPart : FragmentNCName ; -fragment FragNCNameStartChar - : 'A'..'Z' - | '_' - | 'a'..'z' - | '\u00C0'..'\u00D6' - | '\u00D8'..'\u00F6' - | '\u00F8'..'\u02FF' - | '\u0370'..'\u037D' - | '\u037F'..'\u1FFF' - | '\u200C'..'\u200D' - | '\u2070'..'\u218F' - | '\u2C00'..'\u2FEF' - | '\u3001'..'\uD7FF' - | '\uF900'..'\uFDCF' - | '\uFDF0'..'\uFFFD' - | '\u{10000}'..'\u{EFFFF}' - ; -fragment FragNCNameChar - : FragNCNameStartChar | '-' | '.' | '0'..'9' - | '\u00B7' | '\u0300'..'\u036F' - | '\u203F'..'\u2040' - ; -fragment FragmentNCName : FragNCNameStartChar FragNCNameChar* ; +fragment FragQName : FragPrefixedName | FragUnprefixedName; +fragment FragPrefixedName : FragPrefix ':' FragLocalPart; +fragment FragUnprefixedName : FragLocalPart; +fragment FragPrefix : FragmentNCName; +fragment FragLocalPart : FragmentNCName; +fragment FragNCNameStartChar: + 'A' ..'Z' + | '_' + | 'a' ..'z' + | '\u00C0' ..'\u00D6' + | '\u00D8' ..'\u00F6' + | '\u00F8' ..'\u02FF' + | '\u0370' ..'\u037D' + | '\u037F' ..'\u1FFF' + | '\u200C' ..'\u200D' + | '\u2070' ..'\u218F' + | '\u2C00' ..'\u2FEF' + | '\u3001' ..'\uD7FF' + | '\uF900' ..'\uFDCF' + | '\uFDF0' ..'\uFFFD' + | '\u{10000}' ..'\u{EFFFF}' +; +fragment FragNCNameChar: + FragNCNameStartChar + | '-' + | '.' + | '0' ..'9' + | '\u00B7' + | '\u0300' ..'\u036F' + | '\u203F' ..'\u2040' +; +fragment FragmentNCName: FragNCNameStartChar FragNCNameChar*; // https://www.w3.org/TR/REC-xml/#NT-Char -fragment FragChar : '\u0009' | '\u000a' | '\u000d' - | '\u0020'..'\ud7ff' - | '\ue000'..'\ufffd' - | '\u{10000}'..'\u{10ffff}' - ; +fragment FragChar: + '\u0009' + | '\u000a' + | '\u000d' + | '\u0020' ..'\ud7ff' + | '\ue000' ..'\ufffd' + | '\u{10000}' ..'\u{10ffff}' +; // https://github.com/antlr/grammars-v4/blob/17d3db3fd6a8fc319a12176e0bb735b066ec0616/xpath/xpath31/XPath31.g4#L389 -Whitespace : ('\u000d' | '\u000a' | '\u0020' | '\u0009')+ -> skip ; +Whitespace: ('\u000d' | '\u000a' | '\u0020' | '\u0009')+ -> skip; // Not per spec. Specified for testing. -SEMI : ';' ; +SEMI: ';'; diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/AbstractCustomJavaDataType.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/AbstractCustomJavaDataType.java index e5ad1b43a..d42b85329 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/AbstractCustomJavaDataType.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/AbstractCustomJavaDataType.java @@ -1,87 +1,87 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype; - -import gov.nist.secauto.metaschema.core.util.ObjectUtils; - -import java.util.Objects; - -import edu.umd.cs.findbugs.annotations.NonNull; - -/** - * A common base implementation of a custom Java object providing an underlying - * implementation of a data type. - * - * @param - * the bound object type supported by this data type - * @param - * the inner value of the data type object - */ -public abstract class AbstractCustomJavaDataType, VALUE> - implements ICustomJavaDataType { - @NonNull - private final VALUE value; - - /** - * Construct a new instance of a custom Java object-based data value. - * - * @param value - * the bound object that the data type is based on - */ - protected AbstractCustomJavaDataType(@NonNull VALUE value) { - this.value = ObjectUtils.requireNonNull(value, "value"); - } - - /** - * Get the bound Java object value. - * - * @return the bound object - */ - @NonNull - public VALUE getValue() { - return value; - } - // - // public void setValue(T value) { - // this.value = value; - // } - - @Override - public int hashCode() { - return value.hashCode(); - } - - @Override - public boolean equals(Object obj) { - return Objects.equals(value, obj); - } - - @Override - public String toString() { - return value.toString(); - } -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.datatype; + +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.Objects; + +import edu.umd.cs.findbugs.annotations.NonNull; + +/** + * A common base implementation of a custom Java object providing an underlying + * implementation of a data type. + * + * @param + * the bound object type supported by this data type + * @param + * the inner value of the data type object + */ +public abstract class AbstractCustomJavaDataType, VALUE> + implements ICustomJavaDataType { + @NonNull + private final VALUE value; + + /** + * Construct a new instance of a custom Java object-based data value. + * + * @param value + * the bound object that the data type is based on + */ + protected AbstractCustomJavaDataType(@NonNull VALUE value) { + this.value = ObjectUtils.requireNonNull(value, "value"); + } + + /** + * Get the bound Java object value. + * + * @return the bound object + */ + @NonNull + public VALUE getValue() { + return value; + } + // + // public void setValue(T value) { + // this.value = value; + // } + + @Override + public int hashCode() { + return value.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return Objects.equals(value, obj); + } + + @Override + public String toString() { + return value.toString(); + } +} 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 9cad33bc4..8908f6d36 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 @@ -1,68 +1,68 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype; - -import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem; - -import edu.umd.cs.findbugs.annotations.NonNull; - -/** - * Provides a Java type adapter implementation for data types that are based on - * {@link ICustomJavaDataType}. - * - * @param - * the Java type this adapter supports, which is based on - * {@link ICustomJavaDataType} - * @param - * the Metapath item type associated with the adapter - */ -public abstract class AbstractCustomJavaDataTypeAdapter< - TYPE extends ICustomJavaDataType< - TYPE>, - ITEM_TYPE extends IAnyAtomicItem> - extends AbstractDataTypeAdapter { - - /** - * Construct a new Java type adapter for the class based on - * {@link ICustomJavaDataType}. - * - * @param clazz - * a data type class based on {@link ICustomJavaDataType} - */ - public AbstractCustomJavaDataTypeAdapter(@NonNull Class clazz) { - super(clazz); - } - - @SuppressWarnings("unchecked") - @Override - public TYPE copy(Object obj) { - // Datatype-based types are required to provide a copy method. Delegate to this - // method. - return ((TYPE) obj).copy(); - } - -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.datatype; + +import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem; + +import edu.umd.cs.findbugs.annotations.NonNull; + +/** + * Provides a Java type adapter implementation for data types that are based on + * {@link ICustomJavaDataType}. + * + * @param + * the Java type this adapter supports, which is based on + * {@link ICustomJavaDataType} + * @param + * the Metapath item type associated with the adapter + */ +public abstract class AbstractCustomJavaDataTypeAdapter< + TYPE extends ICustomJavaDataType< + TYPE>, + ITEM_TYPE extends IAnyAtomicItem> + extends AbstractDataTypeAdapter { + + /** + * Construct a new Java type adapter for the class based on + * {@link ICustomJavaDataType}. + * + * @param clazz + * a data type class based on {@link ICustomJavaDataType} + */ + public AbstractCustomJavaDataTypeAdapter(@NonNull Class clazz) { + super(clazz); + } + + @SuppressWarnings("unchecked") + @Override + public TYPE copy(Object obj) { + // Datatype-based types are required to provide a copy method. Delegate to this + // method. + return ((TYPE) obj).copy(); + } + +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/AbstractDataTypeProvider.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/AbstractDataTypeProvider.java index 256bb755a..9fac25c1a 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/AbstractDataTypeProvider.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/AbstractDataTypeProvider.java @@ -61,7 +61,7 @@ public List> getJavaTypeAdapters() { * if another type adapter has no name */ protected void registerDatatype(@NonNull IDataTypeAdapter adapter) { - if (adapter.getNames().size() == 0) { + if (adapter.getNames().isEmpty()) { throw new IllegalArgumentException("The adapter has no name: " + adapter.getClass().getName()); } synchronized (this) { diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/DataTypeService.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/DataTypeService.java index 84db86536..0c705ad0f 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/DataTypeService.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/DataTypeService.java @@ -39,6 +39,8 @@ import java.util.function.Function; import java.util.stream.Collectors; +import javax.xml.namespace.QName; + import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; import nl.talsmasoftware.lazy4j.Lazy; @@ -51,8 +53,9 @@ public final class DataTypeService { private static final Logger LOGGER = LogManager.getLogger(DataTypeService.class); private static final Lazy INSTANCE = Lazy.lazy(() -> new DataTypeService()); - private Map> libraryByName; - private Map>, IDataTypeAdapter> libraryByClass; + private final Map> typeByName; + private final Map> typeByQName; + private final Map>, IDataTypeAdapter> typeByClass; /** * Get the singleton service instance, which will be lazy constructed on first @@ -67,57 +70,36 @@ public static DataTypeService getInstance() { } private DataTypeService() { - load(); - } - - /** - * Lookup a specific {@link IDataTypeAdapter} instance by its name. - * - * @param name - * the data type name of data type adapter to get the instance for - * @return the instance or {@code null} if the instance is unknown to the type - * system - */ - @Nullable - public IDataTypeAdapter getJavaTypeAdapterByName(@NonNull String name) { - return libraryByName.get(name); - } - - /** - * Lookup a specific {@link IDataTypeAdapter} instance by its class. - * - * @param clazz - * the adapter class to get the instance for - * @param - * the type of the requested adapter - * @return the instance or {@code null} if the instance is unknown to the type - * system - */ - @SuppressWarnings("unchecked") - @Nullable - public > TYPE getJavaTypeAdapterByClass(@NonNull Class clazz) { - return (TYPE) libraryByClass.get(clazz); - } - /** - * Load available data types registered with the {@link IDataTypeProvider} SPI. - * - * @throws IllegalStateException - * if there are two adapters with the same name - */ - private void load() { ServiceLoader loader = ServiceLoader.load(IDataTypeProvider.class); List> dataTypes = loader.stream() .map(Provider::get) .flatMap(provider -> provider.getJavaTypeAdapters().stream()) .collect(Collectors.toList()); - Map> libraryByName = dataTypes.stream() + Map> typeByName = dataTypes.stream() .flatMap(dataType -> dataType.getNames().stream() - .map(name -> Map.entry(name, dataType))) + .map(qname -> Map.entry(qname.getLocalPart(), dataType))) .collect(CustomCollectors.toMap( Map.Entry::getKey, - (entry) -> entry.getValue(), + Map.Entry::getValue, + (key, v1, v2) -> { + if (LOGGER.isWarnEnabled()) { + LOGGER.warn("Data types '{}' and '{}' have duplicate name '{}'. Using the first.", + v1.getClass().getName(), + v2.getClass().getName(), + key); + } + return v1; + }, + ConcurrentHashMap::new)); + + Map> typeByQName = dataTypes.stream() + .flatMap(dataType -> dataType.getNames().stream() + .map(qname -> Map.entry(qname, dataType))) + .collect(CustomCollectors.toMap( + Map.Entry::getKey, + Map.Entry::getValue, (key, v1, v2) -> { if (LOGGER.isWarnEnabled()) { LOGGER.warn("Data types '{}' and '{}' have duplicate name '{}'. Using the first.", @@ -130,7 +112,7 @@ private void load() { ConcurrentHashMap::new)); @SuppressWarnings({ "unchecked", "null" }) Map>, - IDataTypeAdapter> libraryByClass = dataTypes.stream() + IDataTypeAdapter> typeByClass = dataTypes.stream() .collect(CustomCollectors.toMap( dataType -> (Class>) dataType.getClass(), Function.identity(), @@ -142,10 +124,50 @@ private void load() { return v1; }, ConcurrentHashMap::new)); + this.typeByName = typeByName; + this.typeByQName = typeByQName; + this.typeByClass = typeByClass; + } + + /** + * Lookup a specific {@link IDataTypeAdapter} instance by its name. + * + * @param qname + * the qualified name of data type adapter to get the instance for + * @return the instance or {@code null} if the instance is unknown to the type + * system + */ + @Nullable + public IDataTypeAdapter getJavaTypeAdapterByQName(@NonNull QName qname) { + return typeByQName.get(qname); + } - synchronized (this) { - this.libraryByName = libraryByName; - this.libraryByClass = libraryByClass; - } + /** + * Lookup a specific {@link IDataTypeAdapter} instance by its name. + * + * @param name + * the name of data type adapter to get the instance for + * @return the instance or {@code null} if the instance is unknown to the type + * system + */ + @Nullable + public IDataTypeAdapter getJavaTypeAdapterByName(@NonNull String name) { + return typeByName.get(name); + } + + /** + * Lookup a specific {@link IDataTypeAdapter} instance by its class. + * + * @param clazz + * the adapter class to get the instance for + * @param + * the type of the requested adapter + * @return the instance or {@code null} if the instance is unknown to the type + * system + */ + @SuppressWarnings("unchecked") + @Nullable + public > TYPE getJavaTypeAdapterByClass(@NonNull Class clazz) { + return (TYPE) typeByClass.get(clazz); } } 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 826c26f48..18c2f14b8 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 @@ -1,388 +1,388 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype; - -import com.fasterxml.jackson.core.JsonGenerator; -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; - -import org.codehaus.stax2.XMLEventReader2; -import org.codehaus.stax2.XMLStreamWriter2; -import org.codehaus.stax2.evt.XMLEventFactory2; - -import java.io.IOException; -import java.lang.reflect.Field; -import java.util.List; -import java.util.function.Supplier; - -import javax.xml.namespace.QName; -import javax.xml.stream.XMLEventWriter; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.events.StartElement; -import javax.xml.stream.events.XMLEvent; - -import edu.umd.cs.findbugs.annotations.NonNull; - -public interface IDataTypeAdapter { - - /** - * Get the metaschema type names associated with this adapter. This name must be - * unique with respect to all other metaschema types. - *

- * At least one name must be provided, with the first name being the most - * preferred name. - * - * @return the name - */ - @NonNull - List getNames(); - - /** - * The JSON primative type of the data type. - * - * @return the JSON data type - */ - JsonFormatTypes getJsonRawType(); - - /** - * Get the most preferred name for this data type. - * - * @return the name - */ - @NonNull - default String getPreferredName() { - return ObjectUtils.notNull(getNames().iterator().next()); - } - - /** - * Get the Java class supported by this adapter. - * - * @return the Java class - */ - @NonNull - Class getJavaClass(); - - /** - * Casts the provided value to the type associated with this adapter. - * - * @param value - * a value of the provided type - * @return the typed value - */ - @NonNull - TYPE toValue(@NonNull Object value); - - /** - * Gets the value as a string suitable for writing as text. This is intended for - * data types that have a simple string-based structure in XML and JSON, such as - * for XML attributes or JSON keys. An adapter for a complex data structures - * that consist of XML elements will throw an - * {@link UnsupportedOperationException} when this is called. - * - * @param value - * the data to formatted as a string - * @return a string - * @throws UnsupportedOperationException - * if the data type cannot be represented as a string - */ - @NonNull - String asString(@NonNull Object value); - - /** - * Create a copy of the provided value. - * - * @param obj - * the value to copy - * @return the copy - */ - @NonNull - TYPE copy(@NonNull Object obj); - - /** - * Determines if the data type is an atomic, scalar value. Complex structures - * such as Markup are not considered atomic. - * - * @return {@code true} if the data type is an atomic scalar value, or - * {@code false} otherwise - */ - default boolean isAtomic() { - return true; - } - - /** - * Get the java type of the associated item. - * - * @return the java associated item type - */ - @NonNull - Class getItemClass(); - - /** - * Construct a new item of this type using the provided value. - * - * @param value - * the item's value - * @return a new item - */ - // TODO: markup types are not atomic values. Figure out a better base type - // (i.e., IValuedItem) - @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 - */ - @NonNull - IAnyAtomicItem cast(IAnyAtomicItem item); - - /** - * Indicates if the adapter will parse the {@link XMLEvent#START_ELEMENT} before - * parsing the value data. - * - * @return {@code true} if the adapter requires the start element for parsing, - * or {@code false} otherwise - */ - // TODO; implement or remove this - boolean isParsingStartElement(); - - /** - * Determines if adapter can parse the next element. The next element's - * {@link QName} is provided for this purpose. - *

- * This will be called when the parser encounter's an element it does not - * recognize. This gives the adapter a chance to request parsing of the data. - * - * @param nextElementQName - * the next element's namespace-qualified name - * @return {@code true} if the adapter will parse the element, or {@code false} - * otherwise - */ - boolean canHandleQName(@NonNull QName nextElementQName); - - /** - * Parses a provided string. Used to parse XML attributes, simple XML character - * data, and JSON/YAML property values. - * - * @param value - * the string value to parse - * @return the parsed data as the adapter's type - * @throws IllegalArgumentException - * if the data is not valid to the data type - */ - @NonNull - TYPE parse(@NonNull String value); - - /** - * This method is expected to parse content starting at the next event. Parsing - * will continue until the next event represents content that is not handled by - * this adapter. This means the event stream should be positioned after any - * {@link XMLEvent#END_ELEMENT} that corresponds to an - * {@link XMLEvent#START_ELEMENT} parsed by this adapter. - *

- * If {@link #isParsingStartElement()} returns {@code true}, then the first - * event to parse will be the {@link XMLEvent#START_ELEMENT} for the element - * that contains the value data, then the value data. If this is the case, this - * method must also parse the corresponding {@link XMLEvent#END_ELEMENT}. - * Otherwise, the first event to parse will be the value data. - *

- * The value data is expected to be parsed completely, leaving the event stream - * on a peeked event corresponding to content that is not handled by this - * method. - * - * @param eventReader - * the XML parser used to read the parsed value - * @return the parsed value - * @throws IOException - * if a parsing error occurs - */ - @NonNull - TYPE parse(@NonNull XMLEventReader2 eventReader) throws IOException; - - /** - * Parses a JSON property value. - * - * @param parser - * the JSON parser used to read the parsed value - * @return the parsed value - * @throws IOException - * if a parsing error occurs - */ - @NonNull - TYPE parse(@NonNull JsonParser parser) throws IOException; - - /** - * Parses a provided string using {@link #parse(String)}. - *

- * This method may pre-parse the data and then return copies, since the data can - * only be parsed once, but the supplier might be called multiple times. - * - * @param value - * the string value to parse - * @return a supplier that will provide new instances of the parsed data - * @throws IOException - * if an error occurs while parsing - * @see #parse(String) - */ - @NonNull - default Supplier parseAndSupply(@NonNull String value) throws IOException { - TYPE retval = parse(value); - return () -> copy(retval); - } - - /** - * Parses a provided string using - * {@link IDataTypeAdapter#parse(XMLEventReader2)}. - *

- * This method may pre-parse the data and then return copies, since the data can - * only be parsed once, but the supplier might be called multiple times. - * - * @param eventReader - * the XML parser used to read the parsed value - * @return a supplier that will provide new instances of the parsed data - * @throws IOException - * if an error occurs while parsing - * @see #parse(String) - * @see #parse(XMLEventReader2) - */ - @NonNull - default Supplier parseAndSupply(@NonNull XMLEventReader2 eventReader) throws IOException { - TYPE retval = parse(eventReader); - return () -> copy(retval); - } - - /** - * Parses a provided string using {@link #parse(JsonParser)}. - *

- * This method may pre-parse the data and then return copies, since the data can - * only be parsed once, but the supplier might be called multiple times. - * - * @param parser - * the JSON parser used to read the parsed value - * @return a supplier that will provide new instances of the parsed data - * @throws IOException - * if an error occurs while parsing - * @see #parse(String) - * @see #parse(JsonParser) - */ - @NonNull - default Supplier parseAndSupply(@NonNull JsonParser parser) throws IOException { - TYPE retval = parse(parser); - return () -> copy(retval); - } - - /** - * Writes the provided Java class instance data as XML. The parent element - * information is provided as a {@link StartElement} event, which allows - * namespace information to be obtained from the parent element using the - * {@link StartElement#getName()} and {@link StartElement#getNamespaceContext()} - * methods, which can be used when writing the provided instance value. - * - * @param instance - * the {@link Field} instance value to write - * @param parent - * the {@link StartElement} XML event that is the parent of the data to - * write - * @param eventFactory - * the XML event factory used to generate XML writing events - * @param eventWriter - * the XML writer used to output XML as events - * @throws XMLStreamException - * if an unexpected error occurred while processing the XML output - * @throws IOException - * if an unexpected error occurred while writing to the output stream - */ - void writeXmlValue(@NonNull Object instance, @NonNull StartElement parent, @NonNull XMLEventFactory2 eventFactory, - @NonNull XMLEventWriter eventWriter) - throws IOException, XMLStreamException; - - /** - * Writes the provided Java class instance data as XML. The parent element - * information is provided as an XML {@link QName}, which allows namespace - * information to be obtained from the parent element. Additional namespace - * information can be gathered using the - * {@link XMLStreamWriter2#getNamespaceContext()} method, which can be used when - * writing the provided instance value. - * - * @param instance - * the {@link Field} instance value to write - * @param parentName - * the qualified name of the XML data's parent element - * @param writer - * the XML writer used to output the XML data - * @throws XMLStreamException - * if an unexpected error occurred while processing the XML output - */ - void writeXmlValue(@NonNull Object instance, @NonNull QName parentName, @NonNull XMLStreamWriter2 writer) - throws XMLStreamException; - - /** - * Writes the provided Java class instance as a JSON/YAML field value. - * - * @param instance - * the {@link Field} instance value to write - * @param writer - * the JSON/YAML writer used to output the JSON/YAML data - * @throws IOException - * if an unexpected error occurred while writing the JSON/YAML output - */ - void writeJsonValue(@NonNull Object instance, @NonNull JsonGenerator writer) throws IOException; - - /** - * Gets the default value to use as the JSON/YAML field name for a Metaschema - * field value if no JSON value key flag or name is configured. - * - * @return the default field name to use - */ - @NonNull - String getDefaultJsonValueKey(); - - /** - * Determines if the data type's value is allowed to be unwrapped in XML when - * the value is a field value. - * - * @return {@code true} if allowed, or {@code false} otherwise. - */ - boolean isUnrappedValueAllowedInXml(); - - /** - * Determines if the datatype uses mixed text and element content in XML. - * - * @return {@code true} if the datatype uses mixed text and element content in - * XML, or {@code false} otherwise - */ - boolean isXmlMixed(); -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.datatype; + +import com.fasterxml.jackson.core.JsonGenerator; +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; + +import org.codehaus.stax2.XMLEventReader2; +import org.codehaus.stax2.XMLStreamWriter2; +import org.codehaus.stax2.evt.XMLEventFactory2; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.List; +import java.util.function.Supplier; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public interface IDataTypeAdapter { + + /** + * Get the metaschema type names associated with this adapter. This name must be + * unique with respect to all other metaschema types. + *

+ * At least one name must be provided, with the first name being the most + * preferred name. + * + * @return the name + */ + @NonNull + List getNames(); + + /** + * Get the most preferred name for this data type. + * + * @return the name + */ + @NonNull + default QName getPreferredName() { + return ObjectUtils.notNull(getNames().iterator().next()); + } + + /** + * The JSON primative type of the data type. + * + * @return the JSON data type + */ + JsonFormatTypes getJsonRawType(); + + /** + * Get the Java class supported by this adapter. + * + * @return the Java class + */ + @NonNull + Class getJavaClass(); + + /** + * Casts the provided value to the type associated with this adapter. + * + * @param value + * a value of the provided type + * @return the typed value + */ + @NonNull + TYPE toValue(@NonNull Object value); + + /** + * Gets the value as a string suitable for writing as text. This is intended for + * data types that have a simple string-based structure in XML and JSON, such as + * for XML attributes or JSON keys. An adapter for a complex data structures + * that consist of XML elements will throw an + * {@link UnsupportedOperationException} when this is called. + * + * @param value + * the data to formatted as a string + * @return a string + * @throws UnsupportedOperationException + * if the data type cannot be represented as a string + */ + @NonNull + String asString(@NonNull Object value); + + /** + * Create a copy of the provided value. + * + * @param obj + * the value to copy + * @return the copy + */ + @NonNull + TYPE copy(@NonNull Object obj); + + /** + * Determines if the data type is an atomic, scalar value. Complex structures + * such as Markup are not considered atomic. + * + * @return {@code true} if the data type is an atomic scalar value, or + * {@code false} otherwise + */ + default boolean isAtomic() { + return true; + } + + /** + * Get the java type of the associated item. + * + * @return the java associated item type + */ + @NonNull + Class getItemClass(); + + /** + * Construct a new item of this type using the provided value. + * + * @param value + * the item's value + * @return a new item + */ + // TODO: markup types are not atomic values. Figure out a better base type + // (i.e., IValuedItem) + @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 + */ + @NonNull + IAnyAtomicItem cast(IAnyAtomicItem item); + + /** + * Indicates if the adapter will parse the {@link XMLEvent#START_ELEMENT} before + * parsing the value data. + * + * @return {@code true} if the adapter requires the start element for parsing, + * or {@code false} otherwise + */ + // TODO; implement or remove this + boolean isParsingStartElement(); + + /** + * Determines if adapter can parse the next element. The next element's + * {@link QName} is provided for this purpose. + *

+ * This will be called when the parser encounter's an element it does not + * recognize. This gives the adapter a chance to request parsing of the data. + * + * @param nextElementQName + * the next element's namespace-qualified name + * @return {@code true} if the adapter will parse the element, or {@code false} + * otherwise + */ + boolean canHandleQName(@NonNull QName nextElementQName); + + /** + * Parses a provided string. Used to parse XML attributes, simple XML character + * data, and JSON/YAML property values. + * + * @param value + * the string value to parse + * @return the parsed data as the adapter's type + * @throws IllegalArgumentException + * if the data is not valid to the data type + */ + @NonNull + TYPE parse(@NonNull String value); + + /** + * This method is expected to parse content starting at the next event. Parsing + * will continue until the next event represents content that is not handled by + * this adapter. This means the event stream should be positioned after any + * {@link XMLEvent#END_ELEMENT} that corresponds to an + * {@link XMLEvent#START_ELEMENT} parsed by this adapter. + *

+ * If {@link #isParsingStartElement()} returns {@code true}, then the first + * event to parse will be the {@link XMLEvent#START_ELEMENT} for the element + * that contains the value data, then the value data. If this is the case, this + * method must also parse the corresponding {@link XMLEvent#END_ELEMENT}. + * Otherwise, the first event to parse will be the value data. + *

+ * The value data is expected to be parsed completely, leaving the event stream + * on a peeked event corresponding to content that is not handled by this + * method. + * + * @param eventReader + * the XML parser used to read the parsed value + * @return the parsed value + * @throws IOException + * if a parsing error occurs + */ + @NonNull + TYPE parse(@NonNull XMLEventReader2 eventReader) throws IOException; + + /** + * Parses a JSON property value. + * + * @param parser + * the JSON parser used to read the parsed value + * @return the parsed value + * @throws IOException + * if a parsing error occurs + */ + @NonNull + TYPE parse(@NonNull JsonParser parser) throws IOException; + + /** + * Parses a provided string using {@link #parse(String)}. + *

+ * This method may pre-parse the data and then return copies, since the data can + * only be parsed once, but the supplier might be called multiple times. + * + * @param value + * the string value to parse + * @return a supplier that will provide new instances of the parsed data + * @throws IOException + * if an error occurs while parsing + * @see #parse(String) + */ + @NonNull + default Supplier parseAndSupply(@NonNull String value) throws IOException { + TYPE retval = parse(value); + return () -> copy(retval); + } + + /** + * Parses a provided string using + * {@link IDataTypeAdapter#parse(XMLEventReader2)}. + *

+ * This method may pre-parse the data and then return copies, since the data can + * only be parsed once, but the supplier might be called multiple times. + * + * @param eventReader + * the XML parser used to read the parsed value + * @return a supplier that will provide new instances of the parsed data + * @throws IOException + * if an error occurs while parsing + * @see #parse(String) + * @see #parse(XMLEventReader2) + */ + @NonNull + default Supplier parseAndSupply(@NonNull XMLEventReader2 eventReader) throws IOException { + TYPE retval = parse(eventReader); + return () -> copy(retval); + } + + /** + * Parses a provided string using {@link #parse(JsonParser)}. + *

+ * This method may pre-parse the data and then return copies, since the data can + * only be parsed once, but the supplier might be called multiple times. + * + * @param parser + * the JSON parser used to read the parsed value + * @return a supplier that will provide new instances of the parsed data + * @throws IOException + * if an error occurs while parsing + * @see #parse(String) + * @see #parse(JsonParser) + */ + @NonNull + default Supplier parseAndSupply(@NonNull JsonParser parser) throws IOException { + TYPE retval = parse(parser); + return () -> copy(retval); + } + + /** + * Writes the provided Java class instance data as XML. The parent element + * information is provided as a {@link StartElement} event, which allows + * namespace information to be obtained from the parent element using the + * {@link StartElement#getName()} and {@link StartElement#getNamespaceContext()} + * methods, which can be used when writing the provided instance value. + * + * @param instance + * the {@link Field} instance value to write + * @param parent + * the {@link StartElement} XML event that is the parent of the data to + * write + * @param eventFactory + * the XML event factory used to generate XML writing events + * @param eventWriter + * the XML writer used to output XML as events + * @throws XMLStreamException + * if an unexpected error occurred while processing the XML output + * @throws IOException + * if an unexpected error occurred while writing to the output stream + */ + void writeXmlValue(@NonNull Object instance, @NonNull StartElement parent, @NonNull XMLEventFactory2 eventFactory, + @NonNull XMLEventWriter eventWriter) + throws IOException, XMLStreamException; + + /** + * Writes the provided Java class instance data as XML. The parent element + * information is provided as an XML {@link QName}, which allows namespace + * information to be obtained from the parent element. Additional namespace + * information can be gathered using the + * {@link XMLStreamWriter2#getNamespaceContext()} method, which can be used when + * writing the provided instance value. + * + * @param instance + * the {@link Field} instance value to write + * @param parentName + * the qualified name of the XML data's parent element + * @param writer + * the XML writer used to output the XML data + * @throws XMLStreamException + * if an unexpected error occurred while processing the XML output + */ + void writeXmlValue(@NonNull Object instance, @NonNull QName parentName, @NonNull XMLStreamWriter2 writer) + throws XMLStreamException; + + /** + * Writes the provided Java class instance as a JSON/YAML field value. + * + * @param instance + * the {@link Field} instance value to write + * @param writer + * the JSON/YAML writer used to output the JSON/YAML data + * @throws IOException + * if an unexpected error occurred while writing the JSON/YAML output + */ + void writeJsonValue(@NonNull Object instance, @NonNull JsonGenerator writer) throws IOException; + + /** + * Gets the default value to use as the JSON/YAML field name for a Metaschema + * field value if no JSON value key flag or name is configured. + * + * @return the default field name to use + */ + @NonNull + String getDefaultJsonValueKey(); + + /** + * Determines if the data type's value is allowed to be unwrapped in XML when + * the value is a field value. + * + * @return {@code true} if allowed, or {@code false} otherwise. + */ + boolean isUnrappedValueAllowedInXml(); + + /** + * Determines if the datatype uses mixed text and element content in XML. + * + * @return {@code true} if the datatype uses mixed text and element content in + * XML, or {@code false} otherwise + */ + boolean isXmlMixed(); +} 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 4e40ba80d..abd644013 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 @@ -1,101 +1,104 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype.adapter; - -import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes; - -import gov.nist.secauto.metaschema.core.datatype.AbstractDataTypeAdapter; -import gov.nist.secauto.metaschema.core.metapath.item.atomic.IBase64BinaryItem; -import gov.nist.secauto.metaschema.core.util.ObjectUtils; - -import java.nio.ByteBuffer; -import java.util.Base64; -import java.util.List; - -import edu.umd.cs.findbugs.annotations.NonNull; - -public class Base64Adapter - extends AbstractDataTypeAdapter { - @NonNull - private static final List NAMES = ObjectUtils.notNull( - List.of( - "base64", - // for backwards compatibility with original type name - "base64Binary")); - - Base64Adapter() { - super(ByteBuffer.class); - } - - @Override - public List getNames() { - return NAMES; - } - - @Override - 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); - } - - @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(); - readOnlyCopy.flip(); - clone.put(readOnlyCopy); - return clone; - } - - @SuppressWarnings("null") - @Override - public String asString(Object value) { - Base64.Encoder encoder = Base64.getEncoder(); - return encoder.encodeToString(((ByteBuffer) value).array()); - } - - @Override - public Class getItemClass() { - return IBase64BinaryItem.class; - } - - @Override - public IBase64BinaryItem newItem(Object value) { - ByteBuffer item = toValue(value); - return IBase64BinaryItem.valueOf(item); - } - -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.datatype.adapter; + +import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes; + +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.IBase64BinaryItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.nio.ByteBuffer; +import java.util.Base64; +import java.util.List; + +import javax.xml.namespace.QName; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class Base64Adapter + extends AbstractDataTypeAdapter { + @NonNull + private static final List NAMES = ObjectUtils.notNull( + List.of( + new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "base64"), + // for backwards compatibility with original type name + new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "base64Binary"))); + + Base64Adapter() { + super(ByteBuffer.class); + } + + @Override + public List getNames() { + return NAMES; + } + + @Override + 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); + } + + @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(); + readOnlyCopy.flip(); + clone.put(readOnlyCopy); + return clone; + } + + @SuppressWarnings("null") + @Override + public String asString(Object value) { + Base64.Encoder encoder = Base64.getEncoder(); + return encoder.encodeToString(((ByteBuffer) value).array()); + } + + @Override + public Class getItemClass() { + return IBase64BinaryItem.class; + } + + @Override + public IBase64BinaryItem newItem(Object value) { + ByteBuffer item = toValue(value); + return IBase64BinaryItem.valueOf(item); + } + +} 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 133f8f0dc..9fa446493 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 @@ -1,156 +1,159 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype.adapter; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes; - -import gov.nist.secauto.metaschema.core.datatype.AbstractDataTypeAdapter; -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; -import java.util.List; - -import edu.umd.cs.findbugs.annotations.NonNull; - -public class BooleanAdapter - extends AbstractDataTypeAdapter { - @NonNull - private static final List NAMES = ObjectUtils.notNull( - List.of("boolean")); - - BooleanAdapter() { - super(Boolean.class); - } - - @Override - public List getNames() { - return NAMES; - } - - @Override - public JsonFormatTypes getJsonRawType() { - return JsonFormatTypes.BOOLEAN; - } - - @SuppressWarnings("null") - @Override - public Boolean parse(String value) { - return Boolean.valueOf(value); - } - - @Override - public Boolean parse(JsonParser parser) throws IOException { - Boolean value = parser.getBooleanValue(); - // skip over value - parser.nextToken(); - return value; - } - - @Override - public void writeJsonValue(Object value, JsonGenerator generator) - throws IOException { - try { - generator.writeBoolean((Boolean) value); - } catch (ClassCastException ex) { - throw new IOException(ex); - } - } - - @Override - public Boolean copy(Object obj) { - // the value is immutable - return (Boolean) obj; - } - - @Override - public Class getItemClass() { - return IBooleanItem.class; - } - - @Override - public IBooleanItem newItem(Object value) { - Boolean item = toValue(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 { - retval = castToBoolean(item.asStringItem()); - } - 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; - } - -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.datatype.adapter; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes; + +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; +import java.util.List; + +import javax.xml.namespace.QName; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class BooleanAdapter + extends AbstractDataTypeAdapter { + @NonNull + private static final List NAMES = ObjectUtils.notNull( + List.of(new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "boolean"))); + + BooleanAdapter() { + super(Boolean.class); + } + + @Override + public List getNames() { + return NAMES; + } + + @Override + public JsonFormatTypes getJsonRawType() { + return JsonFormatTypes.BOOLEAN; + } + + @SuppressWarnings("null") + @Override + public Boolean parse(String value) { + return Boolean.valueOf(value); + } + + @Override + public Boolean parse(JsonParser parser) throws IOException { + Boolean value = parser.getBooleanValue(); + // skip over value + parser.nextToken(); + return value; + } + + @Override + public void writeJsonValue(Object value, JsonGenerator generator) + throws IOException { + try { + generator.writeBoolean((Boolean) value); + } catch (ClassCastException ex) { + throw new IOException(ex); + } + } + + @Override + public Boolean copy(Object obj) { + // the value is immutable + return (Boolean) obj; + } + + @Override + public Class getItemClass() { + return IBooleanItem.class; + } + + @Override + public IBooleanItem newItem(Object value) { + Boolean item = toValue(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 { + retval = castToBoolean(item.asStringItem()); + } + 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 349431e9f..c3beb3d3e 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 @@ -1,147 +1,150 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype.adapter; - -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.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; -import java.time.LocalTime; -import java.time.ZoneOffset; -import java.time.ZonedDateTime; -import java.time.format.DateTimeParseException; -import java.time.temporal.TemporalAccessor; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import edu.umd.cs.findbugs.annotations.NonNull; - -public class DateAdapter - extends AbstractCustomJavaDataTypeAdapter { - @NonNull - private static final List NAMES = ObjectUtils.notNull( - List.of("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})?$"); - - DateAdapter() { - super(Date.class); - } - - @Override - public List getNames() { - return NAMES; - } - - @Override - public JsonFormatTypes getJsonRawType() { - return JsonFormatTypes.STRING; - } - - @Override - public Date parse(String value) { - Matcher matcher = DATE_TIMEZONE.matcher(value); - if (!matcher.matches()) { - throw new IllegalArgumentException("Invalid date: " + value); - } - - String parseValue - = 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 - } 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); - } catch (DateTimeParseException ex2) { - IllegalArgumentException newEx = new IllegalArgumentException(ex2.getLocalizedMessage(), ex2); - newEx.addSuppressed(ex); - throw newEx; // NOPMD - false positive - } - } - } - - @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; - } - - @Override - public Class getItemClass() { - return IDateItem.class; - } - - @Override - public IDateItem newItem(Object value) { - Date item = toValue(value); - return IDateItem.valueOf(item); - } - - @Override - protected @NonNull 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; - } - -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.datatype.adapter; + +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.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; +import java.time.LocalTime; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeParseException; +import java.time.temporal.TemporalAccessor; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.xml.namespace.QName; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class DateAdapter + 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})?$"); + + DateAdapter() { + super(Date.class); + } + + @Override + public List getNames() { + return NAMES; + } + + @Override + public JsonFormatTypes getJsonRawType() { + return JsonFormatTypes.STRING; + } + + @Override + public Date parse(String value) { + Matcher matcher = DATE_TIMEZONE.matcher(value); + if (!matcher.matches()) { + throw new IllegalArgumentException("Invalid date: " + value); + } + + String parseValue + = 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 + } 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); + } catch (DateTimeParseException ex2) { + IllegalArgumentException newEx = new IllegalArgumentException(ex2.getLocalizedMessage(), ex2); + newEx.addSuppressed(ex); + throw newEx; // NOPMD - false positive + } + } + } + + @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; + } + + @Override + public Class getItemClass() { + return IDateItem.class; + } + + @Override + public IDateItem newItem(Object value) { + Date item = toValue(value); + return IDateItem.valueOf(item); + } + + @Override + protected @NonNull 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 90ca1d9e9..0573b3b3f 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 @@ -1,131 +1,134 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype.adapter; - -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.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; -import java.time.ZoneOffset; -import java.time.ZonedDateTime; -import java.time.format.DateTimeParseException; -import java.util.List; - -import edu.umd.cs.findbugs.annotations.NonNull; - -public class DateTimeAdapter - extends AbstractCustomJavaDataTypeAdapter { - @NonNull - private static final List NAMES = ObjectUtils.notNull( - List.of( - "date-time", - // for backwards compatibility with original type name - "dateTime")); - - DateTimeAdapter() { - super(DateTime.class); - } - - @Override - public List getNames() { - return NAMES; - } - - @Override - public JsonFormatTypes getJsonRawType() { - return JsonFormatTypes.STRING; - } - - @SuppressWarnings("null") - @Override - public DateTime parse(String value) { - try { - return new DateTime(ZonedDateTime.from(DateFormats.DATE_TIME_WITH_TZ.parse(value)), true); // NOPMD - readability - } catch (DateTimeParseException ex) { - try { - LocalDateTime dateTime = LocalDateTime.from(DateFormats.DATE_TIME_WITHOUT_TZ.parse(value)); - return new DateTime(ZonedDateTime.of(dateTime, ZoneOffset.UTC), false); - } catch (DateTimeParseException ex2) { - IllegalArgumentException newEx = new IllegalArgumentException(ex2.getLocalizedMessage(), ex2); - newEx.addSuppressed(ex); - throw newEx; // NOPMD - it's ok - } - } - } - - @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; - } - - @Override - public Class getItemClass() { - return IDateTimeItem.class; - } - - @Override - public IDateTimeItem newItem(Object value) { - DateTime 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; - } - -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.datatype.adapter; + +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.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; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeParseException; +import java.util.List; + +import javax.xml.namespace.QName; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class DateTimeAdapter + extends AbstractCustomJavaDataTypeAdapter { + @NonNull + private static final List NAMES = ObjectUtils.notNull( + List.of( + new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "date-time"), + // for backwards compatibility with original type name + new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "dateTime"))); + + DateTimeAdapter() { + super(DateTime.class); + } + + @Override + public List getNames() { + return NAMES; + } + + @Override + public JsonFormatTypes getJsonRawType() { + return JsonFormatTypes.STRING; + } + + @SuppressWarnings("null") + @Override + public DateTime parse(String value) { + try { + return new DateTime(ZonedDateTime.from(DateFormats.DATE_TIME_WITH_TZ.parse(value)), true); // NOPMD - readability + } catch (DateTimeParseException ex) { + try { + LocalDateTime dateTime = LocalDateTime.from(DateFormats.DATE_TIME_WITHOUT_TZ.parse(value)); + return new DateTime(ZonedDateTime.of(dateTime, ZoneOffset.UTC), false); + } catch (DateTimeParseException ex2) { + IllegalArgumentException newEx = new IllegalArgumentException(ex2.getLocalizedMessage(), ex2); + newEx.addSuppressed(ex); + throw newEx; // NOPMD - it's ok + } + } + } + + @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; + } + + @Override + public Class getItemClass() { + return IDateTimeItem.class; + } + + @Override + public IDateTimeItem newItem(Object value) { + DateTime 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 ea6c44537..1bfbf278e 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 @@ -1,96 +1,99 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype.adapter; - -import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes; - -import gov.nist.secauto.metaschema.core.datatype.AbstractDataTypeAdapter; -import gov.nist.secauto.metaschema.core.metapath.item.atomic.IDateTimeItem; -import gov.nist.secauto.metaschema.core.util.ObjectUtils; - -import java.time.ZonedDateTime; -import java.time.format.DateTimeParseException; -import java.util.List; - -import edu.umd.cs.findbugs.annotations.NonNull; - -public class DateTimeWithTZAdapter - extends AbstractDataTypeAdapter { - @NonNull - private static final List NAMES = ObjectUtils.notNull( - List.of( - "date-time-with-timezone", - // for backwards compatibility with original type name - "dateTime-with-timezone")); - - DateTimeWithTZAdapter() { - super(ZonedDateTime.class); - } - - @Override - public List getNames() { - return NAMES; - } - - @Override - public JsonFormatTypes getJsonRawType() { - return JsonFormatTypes.STRING; - } - - @SuppressWarnings("null") - @Override - public ZonedDateTime parse(String value) { - try { - return ZonedDateTime.from(DateFormats.DATE_TIME_WITH_TZ.parse(value)); - } catch (DateTimeParseException ex) { - throw new IllegalArgumentException(ex.getLocalizedMessage(), ex); - } - } - - @SuppressWarnings("null") - @Override - public String asString(Object value) { - return DateFormats.DATE_TIME_WITH_TZ.format((ZonedDateTime) value); - } - - @SuppressWarnings("null") - @Override - public ZonedDateTime copy(Object obj) { - return ZonedDateTime.from((ZonedDateTime) obj); - } - - @Override - public Class getItemClass() { - return IDateTimeItem.class; - } - - @Override - public IDateTimeItem newItem(Object value) { - ZonedDateTime item = toValue(value); - return IDateTimeItem.valueOf(item); - } -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.datatype.adapter; + +import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes; + +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.IDateTimeItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.time.ZonedDateTime; +import java.time.format.DateTimeParseException; +import java.util.List; + +import javax.xml.namespace.QName; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class DateTimeWithTZAdapter + extends AbstractDataTypeAdapter { + @NonNull + private static final List NAMES = ObjectUtils.notNull( + List.of( + new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "date-time-with-timezone"), + // for backwards compatibility with original type name + new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "dateTime-with-timezone"))); + + DateTimeWithTZAdapter() { + super(ZonedDateTime.class); + } + + @Override + public List getNames() { + return NAMES; + } + + @Override + public JsonFormatTypes getJsonRawType() { + return JsonFormatTypes.STRING; + } + + @SuppressWarnings("null") + @Override + public ZonedDateTime parse(String value) { + try { + return ZonedDateTime.from(DateFormats.DATE_TIME_WITH_TZ.parse(value)); + } catch (DateTimeParseException ex) { + throw new IllegalArgumentException(ex.getLocalizedMessage(), ex); + } + } + + @SuppressWarnings("null") + @Override + public String asString(Object value) { + return DateFormats.DATE_TIME_WITH_TZ.format((ZonedDateTime) value); + } + + @SuppressWarnings("null") + @Override + public ZonedDateTime copy(Object obj) { + return ZonedDateTime.from((ZonedDateTime) obj); + } + + @Override + public Class getItemClass() { + return IDateTimeItem.class; + } + + @Override + public IDateTimeItem newItem(Object value) { + ZonedDateTime item = toValue(value); + return IDateTimeItem.valueOf(item); + } +} 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 f116e3c25..3d0040d7d 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 @@ -1,108 +1,111 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype.adapter; - -import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes; - -import gov.nist.secauto.metaschema.core.datatype.AbstractDataTypeAdapter; -import gov.nist.secauto.metaschema.core.metapath.item.atomic.IDateItem; -import gov.nist.secauto.metaschema.core.util.ObjectUtils; - -import java.time.ZonedDateTime; -import java.time.format.DateTimeParseException; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import edu.umd.cs.findbugs.annotations.NonNull; - -public class DateWithTZAdapter - extends AbstractDataTypeAdapter { - @NonNull - private static final List NAMES = ObjectUtils.notNull( - List.of( - "date-with-timezone")); - 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})$"); - - DateWithTZAdapter() { - super(ZonedDateTime.class); - } - - @Override - public List getNames() { - return NAMES; - } - - @Override - public JsonFormatTypes getJsonRawType() { - return JsonFormatTypes.STRING; - } - - @SuppressWarnings("null") - @Override - public ZonedDateTime parse(String value) { - Matcher matcher = DATE_TIMEZONE.matcher(value); - if (!matcher.matches()) { - throw new IllegalArgumentException("Invalid date: " + value); - } - String parseValue = String.format("%sT00:00:00%s", matcher.group(1), matcher.group(2)); - try { - return ZonedDateTime.from(DateFormats.DATE_TIME_WITH_TZ.parse(parseValue)); - } catch (DateTimeParseException ex) { - throw new IllegalArgumentException(ex.getLocalizedMessage(), ex); - } - } - - @SuppressWarnings("null") - @Override - public String asString(Object value) { - return DateFormats.DATE_WITH_TZ.format((ZonedDateTime) value); - } - - @SuppressWarnings("null") - @Override - public ZonedDateTime copy(Object obj) { - return ZonedDateTime.from((ZonedDateTime) obj); - } - - @Override - public Class getItemClass() { - return IDateItem.class; - } - - @Override - public IDateItem newItem(Object value) { - ZonedDateTime item = toValue(value); - return IDateItem.valueOf(item); - } -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.datatype.adapter; + +import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes; + +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.IDateItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.time.ZonedDateTime; +import java.time.format.DateTimeParseException; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.xml.namespace.QName; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class DateWithTZAdapter + extends AbstractDataTypeAdapter { + @NonNull + private static final List NAMES = ObjectUtils.notNull( + List.of( + new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "date-with-timezone"))); + 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})$"); + + DateWithTZAdapter() { + super(ZonedDateTime.class); + } + + @Override + public List getNames() { + return NAMES; + } + + @Override + public JsonFormatTypes getJsonRawType() { + return JsonFormatTypes.STRING; + } + + @SuppressWarnings("null") + @Override + public ZonedDateTime parse(String value) { + Matcher matcher = DATE_TIMEZONE.matcher(value); + if (!matcher.matches()) { + throw new IllegalArgumentException("Invalid date: " + value); + } + String parseValue = String.format("%sT00:00:00%s", matcher.group(1), matcher.group(2)); + try { + return ZonedDateTime.from(DateFormats.DATE_TIME_WITH_TZ.parse(parseValue)); + } catch (DateTimeParseException ex) { + throw new IllegalArgumentException(ex.getLocalizedMessage(), ex); + } + } + + @SuppressWarnings("null") + @Override + public String asString(Object value) { + return DateFormats.DATE_WITH_TZ.format((ZonedDateTime) value); + } + + @SuppressWarnings("null") + @Override + public ZonedDateTime copy(Object obj) { + return ZonedDateTime.from((ZonedDateTime) obj); + } + + @Override + public Class getItemClass() { + return IDateItem.class; + } + + @Override + public IDateItem newItem(Object value) { + ZonedDateTime item = toValue(value); + return IDateItem.valueOf(item); + } +} 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 9e2e2c795..b058f2eac 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 @@ -29,6 +29,7 @@ import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes; 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.IDayTimeDurationItem; import gov.nist.secauto.metaschema.core.util.ObjectUtils; @@ -36,20 +37,22 @@ import java.time.format.DateTimeParseException; import java.util.List; +import javax.xml.namespace.QName; + import edu.umd.cs.findbugs.annotations.NonNull; public class DayTimeAdapter extends AbstractDataTypeAdapter { @NonNull - private static final List NAMES = ObjectUtils.notNull( - List.of("day-time-duration")); + private static final List NAMES = ObjectUtils.notNull( + List.of(new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "day-time-duration"))); DayTimeAdapter() { super(Duration.class); } @Override - public List getNames() { + public List getNames() { return NAMES; } 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 0754a7cfd..49fd4ee29 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 @@ -1,115 +1,118 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype.adapter; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes; - -import gov.nist.secauto.metaschema.core.datatype.AbstractDataTypeAdapter; -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; -import java.math.BigDecimal; -import java.math.MathContext; -import java.util.List; - -import edu.umd.cs.findbugs.annotations.NonNull; - -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"); - @NonNull - private static final List NAMES = ObjectUtils.notNull( - List.of("decimal")); - - DecimalAdapter() { - super(BigDecimal.class); - } - - @Override - public List getNames() { - return NAMES; - } - - @Override - public JsonFormatTypes getJsonRawType() { - return JsonFormatTypes.NUMBER; - } - - @Override - public BigDecimal parse(String value) { - return new BigDecimal(value, MATH_CONTEXT); - } - - @Override - public void writeJsonValue(Object value, JsonGenerator generator) throws IOException { - try { - generator.writeNumber((BigDecimal) value); - } catch (ClassCastException ex) { - throw new IOException(ex); - } - } - - @Override - public BigDecimal copy(Object obj) { - // a BigDecimal is immutable - return (BigDecimal) obj; - } - - @Override - public Class getItemClass() { - return IDecimalItem.class; - } - - @Override - 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; - } -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.datatype.adapter; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes; + +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; +import java.math.BigDecimal; +import java.math.MathContext; +import java.util.List; + +import javax.xml.namespace.QName; + +import edu.umd.cs.findbugs.annotations.NonNull; + +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"); + @NonNull + private static final List NAMES = ObjectUtils.notNull( + List.of(new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "decimal"))); + + DecimalAdapter() { + super(BigDecimal.class); + } + + @Override + public List getNames() { + return NAMES; + } + + @Override + public JsonFormatTypes getJsonRawType() { + return JsonFormatTypes.NUMBER; + } + + @Override + public BigDecimal parse(String value) { + return new BigDecimal(value, MATH_CONTEXT); + } + + @Override + public void writeJsonValue(Object value, JsonGenerator generator) throws IOException { + try { + generator.writeNumber((BigDecimal) value); + } catch (ClassCastException ex) { + throw new IOException(ex); + } + } + + @Override + public BigDecimal copy(Object obj) { + // a BigDecimal is immutable + return (BigDecimal) obj; + } + + @Override + public Class getItemClass() { + return IDecimalItem.class; + } + + @Override + 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 13b9b8657..9818890a2 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 @@ -1,64 +1,67 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype.adapter; - -import gov.nist.secauto.metaschema.core.metapath.item.atomic.IEmailAddressItem; -import gov.nist.secauto.metaschema.core.util.ObjectUtils; - -import java.util.List; - -import edu.umd.cs.findbugs.annotations.NonNull; - -public class EmailAddressAdapter - extends AbstractStringAdapter { - @NonNull - private static final List NAMES = ObjectUtils.notNull( - List.of( - "email-address", - // for backwards compatibility with original type name - "email")); - - EmailAddressAdapter() { - // avoid general construction - } - - @Override - public List getNames() { - return NAMES; - } - - @Override - public @NonNull Class getItemClass() { - return IEmailAddressItem.class; - } - - @Override - public IEmailAddressItem newItem(Object value) { - String item = asString(value); - return IEmailAddressItem.valueOf(item); - } -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +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.IEmailAddressItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.List; + +import javax.xml.namespace.QName; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class EmailAddressAdapter + extends AbstractStringAdapter { + @NonNull + private static final List NAMES = ObjectUtils.notNull( + List.of( + new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "email-address"), + // for backwards compatibility with original type name + new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "email"))); + + EmailAddressAdapter() { + // avoid general construction + } + + @Override + public List getNames() { + return NAMES; + } + + @Override + public @NonNull Class getItemClass() { + return IEmailAddressItem.class; + } + + @Override + public IEmailAddressItem newItem(Object value) { + String item = asString(value); + return IEmailAddressItem.valueOf(item); + } +} 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 30304b8aa..6b6a8455c 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 @@ -1,61 +1,64 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype.adapter; - -import gov.nist.secauto.metaschema.core.metapath.item.atomic.IHostnameItem; -import gov.nist.secauto.metaschema.core.util.ObjectUtils; - -import java.util.List; - -import edu.umd.cs.findbugs.annotations.NonNull; - -public class HostnameAdapter - extends AbstractStringAdapter { - @NonNull - private static final List NAMES = ObjectUtils.notNull( - List.of("hostname")); - - HostnameAdapter() { - // avoid general construction - } - - @Override - public List getNames() { - return NAMES; - } - - @Override - public @NonNull Class getItemClass() { - return IHostnameItem.class; - } - - @Override - public IHostnameItem newItem(Object value) { - String item = asString(value); - return IHostnameItem.valueOf(item); - } -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +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.IHostnameItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.List; + +import javax.xml.namespace.QName; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class HostnameAdapter + extends AbstractStringAdapter { + @NonNull + private static final List NAMES = ObjectUtils.notNull( + List.of(new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "hostname"))); + + HostnameAdapter() { + // avoid general construction + } + + @Override + public List getNames() { + return NAMES; + } + + @Override + public @NonNull Class getItemClass() { + return IHostnameItem.class; + } + + @Override + public IHostnameItem newItem(Object value) { + String item = asString(value); + return IHostnameItem.valueOf(item); + } +} 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 5c6aeb585..58ad33492 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 @@ -1,97 +1,108 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype.adapter; - -import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes; - -import gov.nist.secauto.metaschema.core.datatype.AbstractDataTypeAdapter; -import gov.nist.secauto.metaschema.core.metapath.item.atomic.IIPv4AddressItem; -import gov.nist.secauto.metaschema.core.util.ObjectUtils; - -import java.util.List; - -import edu.umd.cs.findbugs.annotations.NonNull; -import inet.ipaddr.AddressStringException; -import inet.ipaddr.IPAddressString; -import inet.ipaddr.IPAddressStringParameters; -import inet.ipaddr.IncompatibleAddressException; -import inet.ipaddr.ipv4.IPv4Address; - -public class IPv4AddressAdapter - extends AbstractDataTypeAdapter { - @NonNull - private static final List NAMES = ObjectUtils.notNull( - List.of("ip-v4-address")); - private static final IPAddressStringParameters IP_V_4; - - static { - IP_V_4 = new IPAddressStringParameters.Builder().allowIPv6(false).allowEmpty(false).allowSingleSegment(false) - .allowWildcardedSeparator(false).getIPv4AddressParametersBuilder().allowBinary(false).allowLeadingZeros(false) - .allowPrefixesBeyondAddressSize(false).getParentBuilder().toParams(); - } - - IPv4AddressAdapter() { - super(IPv4Address.class); - } - - @Override - public List getNames() { - return NAMES; - } - - @Override - public JsonFormatTypes getJsonRawType() { - return JsonFormatTypes.STRING; - } - - @SuppressWarnings("null") - @Override - public IPv4Address parse(String value) { - try { - return (IPv4Address) new IPAddressString(value, IP_V_4).toAddress(); - } catch (AddressStringException | IncompatibleAddressException ex) { - throw new IllegalArgumentException(ex.getLocalizedMessage(), ex); - } - } - - @Override - public IPv4Address copy(Object obj) { - // value is immutable - return (IPv4Address) obj; - } - - @Override - public Class getItemClass() { - return IIPv4AddressItem.class; - } - - @Override - public IIPv4AddressItem newItem(Object value) { - IPv4Address item = toValue(value); - return IIPv4AddressItem.valueOf(item); - } -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.datatype.adapter; + +import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes; + +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.IIPv4AddressItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.List; + +import javax.xml.namespace.QName; + +import edu.umd.cs.findbugs.annotations.NonNull; +import inet.ipaddr.AddressStringException; +import inet.ipaddr.IPAddressString; +import inet.ipaddr.IPAddressStringParameters; +import inet.ipaddr.IncompatibleAddressException; +import inet.ipaddr.ipv4.IPv4Address; + +public class IPv4AddressAdapter + extends AbstractDataTypeAdapter { + @NonNull + private static final List NAMES = ObjectUtils.notNull( + List.of(new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "ip-v4-address"))); + private static final IPAddressStringParameters IP_V_4; + + static { + IP_V_4 = new IPAddressStringParameters.Builder() + .allowIPv6(false) + .allowEmpty(false) + .allowSingleSegment(false) + .allowWildcardedSeparator(false) + .getIPv4AddressParametersBuilder() + .allowBinary(false) + .allowLeadingZeros(false) + .allowPrefixesBeyondAddressSize(false) + .getParentBuilder() + .toParams(); + } + + IPv4AddressAdapter() { + super(IPv4Address.class); + } + + @Override + public List getNames() { + return NAMES; + } + + @Override + public JsonFormatTypes getJsonRawType() { + return JsonFormatTypes.STRING; + } + + @SuppressWarnings("null") + @Override + public IPv4Address parse(String value) { + try { + return (IPv4Address) new IPAddressString(value, IP_V_4).toAddress(); + } catch (AddressStringException | IncompatibleAddressException ex) { + throw new IllegalArgumentException(ex.getLocalizedMessage(), ex); + } + } + + @Override + public IPv4Address copy(Object obj) { + // value is immutable + return (IPv4Address) obj; + } + + @Override + public Class getItemClass() { + return IIPv4AddressItem.class; + } + + @Override + public IIPv4AddressItem newItem(Object value) { + IPv4Address item = toValue(value); + return IIPv4AddressItem.valueOf(item); + } +} 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 05ba1bbca..a09300569 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 @@ -1,97 +1,100 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype.adapter; - -import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes; - -import gov.nist.secauto.metaschema.core.datatype.AbstractDataTypeAdapter; -import gov.nist.secauto.metaschema.core.metapath.item.atomic.IIPv6AddressItem; -import gov.nist.secauto.metaschema.core.util.ObjectUtils; - -import java.util.List; - -import edu.umd.cs.findbugs.annotations.NonNull; -import inet.ipaddr.AddressStringException; -import inet.ipaddr.IPAddressString; -import inet.ipaddr.IPAddressStringParameters; -import inet.ipaddr.IncompatibleAddressException; -import inet.ipaddr.ipv6.IPv6Address; - -public class IPv6AddressAdapter - extends AbstractDataTypeAdapter { - @NonNull - private static final List NAMES = ObjectUtils.notNull( - List.of("ip-v6-address")); - private static final IPAddressStringParameters IP_V_6; - - static { - IP_V_6 = new IPAddressStringParameters.Builder().allowIPv4(false).allowEmpty(false).allowSingleSegment(false) - .allowWildcardedSeparator(false).getIPv6AddressParametersBuilder().allowBinary(false) - .allowPrefixesBeyondAddressSize(false).getParentBuilder().toParams(); - } - - IPv6AddressAdapter() { - super(IPv6Address.class); - } - - @Override - public List getNames() { - return NAMES; - } - - @Override - public JsonFormatTypes getJsonRawType() { - return JsonFormatTypes.STRING; - } - - @SuppressWarnings("null") - @Override - public IPv6Address parse(String value) { - try { - return (IPv6Address) new IPAddressString(value, IP_V_6).toAddress(); - } catch (AddressStringException | IncompatibleAddressException ex) { - throw new IllegalArgumentException(ex.getLocalizedMessage(), ex); - } - } - - @Override - public IPv6Address copy(Object obj) { - // value is immutable - return (IPv6Address) obj; - } - - @Override - public Class getItemClass() { - return IIPv6AddressItem.class; - } - - @Override - public IIPv6AddressItem newItem(Object value) { - IPv6Address item = toValue(value); - return IIPv6AddressItem.valueOf(item); - } -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.datatype.adapter; + +import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes; + +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.IIPv6AddressItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.List; + +import javax.xml.namespace.QName; + +import edu.umd.cs.findbugs.annotations.NonNull; +import inet.ipaddr.AddressStringException; +import inet.ipaddr.IPAddressString; +import inet.ipaddr.IPAddressStringParameters; +import inet.ipaddr.IncompatibleAddressException; +import inet.ipaddr.ipv6.IPv6Address; + +public class IPv6AddressAdapter + extends AbstractDataTypeAdapter { + @NonNull + private static final List NAMES = ObjectUtils.notNull( + List.of(new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "ip-v6-address"))); + private static final IPAddressStringParameters IP_V_6; + + static { + IP_V_6 = new IPAddressStringParameters.Builder().allowIPv4(false).allowEmpty(false).allowSingleSegment(false) + .allowWildcardedSeparator(false).getIPv6AddressParametersBuilder().allowBinary(false) + .allowPrefixesBeyondAddressSize(false).getParentBuilder().toParams(); + } + + IPv6AddressAdapter() { + super(IPv6Address.class); + } + + @Override + public List getNames() { + return NAMES; + } + + @Override + public JsonFormatTypes getJsonRawType() { + return JsonFormatTypes.STRING; + } + + @SuppressWarnings("null") + @Override + public IPv6Address parse(String value) { + try { + return (IPv6Address) new IPAddressString(value, IP_V_6).toAddress(); + } catch (AddressStringException | IncompatibleAddressException ex) { + throw new IllegalArgumentException(ex.getLocalizedMessage(), ex); + } + } + + @Override + public IPv6Address copy(Object obj) { + // value is immutable + return (IPv6Address) obj; + } + + @Override + public Class getItemClass() { + return IIPv6AddressItem.class; + } + + @Override + public IIPv6AddressItem newItem(Object value) { + IPv6Address item = toValue(value); + return IIPv6AddressItem.valueOf(item); + } +} 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 2e0684092..02973460d 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 @@ -1,79 +1,82 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype.adapter; - -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; -import java.util.List; - -import edu.umd.cs.findbugs.annotations.NonNull; - -public class IntegerAdapter - extends AbstractIntegerAdapter { - @NonNull - private static final List NAMES = ObjectUtils.notNull( - List.of("integer")); - - IntegerAdapter() { - // avoid general construction - } - - @Override - public List getNames() { - return NAMES; - } - - @Override - public @NonNull Class getItemClass() { - return IIntegerItem.class; - } - - @Override - 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; - } -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +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; +import java.util.List; + +import javax.xml.namespace.QName; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class IntegerAdapter + extends AbstractIntegerAdapter { + @NonNull + private static final List NAMES = ObjectUtils.notNull( + List.of(new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "integer"))); + + IntegerAdapter() { + // avoid general construction + } + + @Override + public List getNames() { + return NAMES; + } + + @Override + public @NonNull Class getItemClass() { + return IIntegerItem.class; + } + + @Override + 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/NcNameAdapter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/adapter/NcNameAdapter.java index 4cb7365a6..4a6c99d26 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 @@ -1,64 +1,67 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype.adapter; - -import gov.nist.secauto.metaschema.core.metapath.item.atomic.INcNameItem; -import gov.nist.secauto.metaschema.core.util.ObjectUtils; - -import java.util.List; - -import edu.umd.cs.findbugs.annotations.NonNull; - -@Deprecated(forRemoval = true, since = "0.7.0") -public class NcNameAdapter - extends AbstractStringAdapter { - @NonNull - private static final List NAMES = ObjectUtils.notNull( - List.of("ncname", - // for backwards compatibility with original type name - "NCName")); - - NcNameAdapter() { - // avoid general construction - } - - @Override - public List getNames() { - return NAMES; - } - - @Override - public Class getItemClass() { - return INcNameItem.class; - } - - @Override - public INcNameItem newItem(Object value) { - String item = asString(value); - return INcNameItem.valueOf(item); - } -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +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.INcNameItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.List; + +import javax.xml.namespace.QName; + +import edu.umd.cs.findbugs.annotations.NonNull; + +@Deprecated(forRemoval = true, since = "0.7.0") +public class NcNameAdapter + extends AbstractStringAdapter { + @NonNull + private static final List NAMES = ObjectUtils.notNull( + List.of(new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "ncname"), + // for backwards compatibility with original type name + new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "NCName"))); + + NcNameAdapter() { + // avoid general construction + } + + @Override + public List getNames() { + return NAMES; + } + + @Override + public Class getItemClass() { + return INcNameItem.class; + } + + @Override + public INcNameItem newItem(Object value) { + String item = asString(value); + return INcNameItem.valueOf(item); + } +} 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 72648415a..23af3d9e3 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 @@ -1,65 +1,68 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype.adapter; - -import gov.nist.secauto.metaschema.core.metapath.item.atomic.INonNegativeIntegerItem; -import gov.nist.secauto.metaschema.core.util.ObjectUtils; - -import java.math.BigInteger; -import java.util.List; - -import edu.umd.cs.findbugs.annotations.NonNull; - -public class NonNegativeIntegerAdapter - extends AbstractIntegerAdapter { - @NonNull - private static final List NAMES = ObjectUtils.notNull( - List.of( - "non-negative-integer", - // for backwards compatibility with original type name - "nonNegativeInteger")); - - NonNegativeIntegerAdapter() { - // avoid general construction - } - - @Override - public List getNames() { - return NAMES; - } - - @Override - public Class getItemClass() { - return INonNegativeIntegerItem.class; - } - - @Override - public INonNegativeIntegerItem newItem(Object value) { - BigInteger item = toValue(value); - return INonNegativeIntegerItem.valueOf(item); - } -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +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.INonNegativeIntegerItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.math.BigInteger; +import java.util.List; + +import javax.xml.namespace.QName; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class NonNegativeIntegerAdapter + extends AbstractIntegerAdapter { + @NonNull + private static final List NAMES = ObjectUtils.notNull( + List.of( + new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "non-negative-integer"), + // for backwards compatibility with original type name + new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "nonNegativeInteger"))); + + NonNegativeIntegerAdapter() { + // avoid general construction + } + + @Override + public List getNames() { + return NAMES; + } + + @Override + public Class getItemClass() { + return INonNegativeIntegerItem.class; + } + + @Override + public INonNegativeIntegerItem newItem(Object value) { + BigInteger item = toValue(value); + return INonNegativeIntegerItem.valueOf(item); + } +} 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 8e9aad093..3eb2f949d 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 @@ -1,65 +1,68 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype.adapter; - -import gov.nist.secauto.metaschema.core.metapath.item.atomic.IPositiveIntegerItem; -import gov.nist.secauto.metaschema.core.util.ObjectUtils; - -import java.math.BigInteger; -import java.util.List; - -import edu.umd.cs.findbugs.annotations.NonNull; - -public class PositiveIntegerAdapter - extends AbstractIntegerAdapter { - @NonNull - private static final List NAMES = ObjectUtils.notNull( - List.of( - "positive-integer", - // for backwards compatibility with original type name - "positiveInteger")); - - PositiveIntegerAdapter() { - // avoid general construction - } - - @Override - public List getNames() { - return NAMES; - } - - @Override - public Class getItemClass() { - return IPositiveIntegerItem.class; - } - - @Override - public IPositiveIntegerItem newItem(Object value) { - BigInteger item = toValue(value); - return IPositiveIntegerItem.valueOf(item); - } -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +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.IPositiveIntegerItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.math.BigInteger; +import java.util.List; + +import javax.xml.namespace.QName; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class PositiveIntegerAdapter + extends AbstractIntegerAdapter { + @NonNull + private static final List NAMES = ObjectUtils.notNull( + List.of( + new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "positive-integer"), + // for backwards compatibility with original type name + new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "positiveInteger"))); + + PositiveIntegerAdapter() { + // avoid general construction + } + + @Override + public List getNames() { + return NAMES; + } + + @Override + public Class getItemClass() { + return IPositiveIntegerItem.class; + } + + @Override + public IPositiveIntegerItem newItem(Object value) { + BigInteger item = toValue(value); + return IPositiveIntegerItem.valueOf(item); + } +} 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 6d58c700b..e2810e229 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 @@ -1,61 +1,64 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype.adapter; - -import gov.nist.secauto.metaschema.core.metapath.item.atomic.IStringItem; -import gov.nist.secauto.metaschema.core.util.ObjectUtils; - -import java.util.List; - -import edu.umd.cs.findbugs.annotations.NonNull; - -public class StringAdapter - extends AbstractStringAdapter { - @NonNull - private static final List NAMES = ObjectUtils.notNull( - List.of("string")); - - StringAdapter() { - // avoid general construction - } - - @Override - public List getNames() { - return NAMES; - } - - @Override - public Class getItemClass() { - return IStringItem.class; - } - - @Override - public @NonNull IStringItem newItem(@NonNull Object value) { - String item = asString(value); - return IStringItem.valueOf(item); - } -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +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.IStringItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.List; + +import javax.xml.namespace.QName; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class StringAdapter + extends AbstractStringAdapter { + @NonNull + private static final List NAMES = ObjectUtils.notNull( + List.of(new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "string"))); + + StringAdapter() { + // avoid general construction + } + + @Override + public List getNames() { + return NAMES; + } + + @Override + public Class getItemClass() { + return IStringItem.class; + } + + @Override + public @NonNull IStringItem newItem(@NonNull Object value) { + String item = asString(value); + return IStringItem.valueOf(item); + } +} 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 327edfe7a..5136d297c 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 @@ -26,25 +26,28 @@ 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.ITokenItem; import gov.nist.secauto.metaschema.core.util.ObjectUtils; import java.util.List; +import javax.xml.namespace.QName; + import edu.umd.cs.findbugs.annotations.NonNull; public class TokenAdapter extends AbstractStringAdapter { @NonNull - private static final List NAMES = ObjectUtils.notNull( - List.of("token")); + private static final List NAMES = ObjectUtils.notNull( + List.of(new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "token"))); TokenAdapter() { // avoid general construction } @Override - public List getNames() { + public List getNames() { return NAMES; } 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 fbfa746ad..f1bb35083 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 @@ -1,83 +1,86 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype.adapter; - -import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes; - -import gov.nist.secauto.metaschema.core.datatype.AbstractDataTypeAdapter; -import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyUriItem; -import gov.nist.secauto.metaschema.core.util.ObjectUtils; - -import java.net.URI; -import java.util.List; - -import edu.umd.cs.findbugs.annotations.NonNull; - -public class UriAdapter - extends AbstractDataTypeAdapter { - @NonNull - private static final List NAMES = ObjectUtils.notNull( - List.of("uri")); - - UriAdapter() { - super(URI.class); - } - - @Override - public List getNames() { - return NAMES; - } - - @Override - public JsonFormatTypes getJsonRawType() { - return JsonFormatTypes.STRING; - } - - @SuppressWarnings("null") - @Override - public URI parse(String value) { - return URI.create(value); - } - - @Override - public URI copy(Object obj) { - // a URI is immutable - return (URI) obj; - } - - @Override - public Class getItemClass() { - return IAnyUriItem.class; - } - - @Override - public IAnyUriItem newItem(Object value) { - URI item = toValue(value); - return IAnyUriItem.valueOf(item); - } - -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.datatype.adapter; + +import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes; + +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.IAnyUriItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.net.URI; +import java.util.List; + +import javax.xml.namespace.QName; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class UriAdapter + extends AbstractDataTypeAdapter { + @NonNull + private static final List NAMES = ObjectUtils.notNull( + List.of(new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "uri"))); + + UriAdapter() { + super(URI.class); + } + + @Override + public List getNames() { + return NAMES; + } + + @Override + public JsonFormatTypes getJsonRawType() { + return JsonFormatTypes.STRING; + } + + @SuppressWarnings("null") + @Override + public URI parse(String value) { + return URI.create(value); + } + + @Override + public URI copy(Object obj) { + // a URI is immutable + return (URI) obj; + } + + @Override + public Class getItemClass() { + return IAnyUriItem.class; + } + + @Override + public IAnyUriItem newItem(Object value) { + URI item = toValue(value); + return IAnyUriItem.valueOf(item); + } + +} 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 e17f4d58b..2e3015bcc 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 @@ -1,82 +1,85 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype.adapter; - -import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes; - -import gov.nist.secauto.metaschema.core.datatype.AbstractDataTypeAdapter; -import gov.nist.secauto.metaschema.core.metapath.item.atomic.IUriReferenceItem; -import gov.nist.secauto.metaschema.core.util.ObjectUtils; - -import java.net.URI; -import java.util.List; - -import edu.umd.cs.findbugs.annotations.NonNull; - -public class UriReferenceAdapter - extends AbstractDataTypeAdapter { - @NonNull - private static final List NAMES = ObjectUtils.notNull( - List.of("uri-reference")); - - UriReferenceAdapter() { - super(URI.class); - } - - @Override - public List getNames() { - return NAMES; - } - - @Override - public JsonFormatTypes getJsonRawType() { - return JsonFormatTypes.STRING; - } - - @SuppressWarnings("null") - @Override - public URI parse(String value) { - return URI.create(value); - } - - @Override - public URI copy(Object obj) { - // a URI is immutable - return (URI) obj; - } - - @Override - public Class getItemClass() { - return IUriReferenceItem.class; - } - - @Override - public IUriReferenceItem newItem(Object value) { - URI item = toValue(value); - return IUriReferenceItem.valueOf(item); - } -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.datatype.adapter; + +import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes; + +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.IUriReferenceItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.net.URI; +import java.util.List; + +import javax.xml.namespace.QName; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class UriReferenceAdapter + extends AbstractDataTypeAdapter { + @NonNull + private static final List NAMES = ObjectUtils.notNull( + List.of(new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "uri-reference"))); + + UriReferenceAdapter() { + super(URI.class); + } + + @Override + public List getNames() { + return NAMES; + } + + @Override + public JsonFormatTypes getJsonRawType() { + return JsonFormatTypes.STRING; + } + + @SuppressWarnings("null") + @Override + public URI parse(String value) { + return URI.create(value); + } + + @Override + public URI copy(Object obj) { + // a URI is immutable + return (URI) obj; + } + + @Override + public Class getItemClass() { + return IUriReferenceItem.class; + } + + @Override + public IUriReferenceItem newItem(Object value) { + URI item = toValue(value); + return IUriReferenceItem.valueOf(item); + } +} 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 fda5a1234..7338723b5 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 @@ -29,6 +29,7 @@ import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes; 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.IUuidItem; import gov.nist.secauto.metaschema.core.util.ObjectUtils; @@ -36,13 +37,15 @@ import java.util.UUID; import java.util.regex.Pattern; +import javax.xml.namespace.QName; + import edu.umd.cs.findbugs.annotations.NonNull; public class UuidAdapter extends AbstractDataTypeAdapter { @NonNull - private static final List NAMES = ObjectUtils.notNull( - List.of("uuid")); + private static final List NAMES = ObjectUtils.notNull( + List.of(new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "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}$"); @@ -51,7 +54,7 @@ public class UuidAdapter } @Override - public List getNames() { + public List getNames() { return NAMES; } 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 0d9190696..b1fcff918 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 @@ -29,6 +29,7 @@ import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes; 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.IYearMonthDurationItem; import gov.nist.secauto.metaschema.core.util.ObjectUtils; @@ -36,20 +37,22 @@ import java.time.format.DateTimeParseException; import java.util.List; +import javax.xml.namespace.QName; + import edu.umd.cs.findbugs.annotations.NonNull; public class YearMonthAdapter extends AbstractDataTypeAdapter { @NonNull - private static final List NAMES = ObjectUtils.notNull( - List.of("year-month-duration")); + private static final List NAMES = ObjectUtils.notNull( + List.of(new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "year-month-duration"))); YearMonthAdapter() { super(Period.class); } @Override - public List getNames() { + public List getNames() { return NAMES; } 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 667e292af..5b5f7ddda 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 @@ -1,300 +1,300 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype.markup; - -import com.ctc.wstx.api.WstxOutputProperties; -import com.ctc.wstx.stax.WstxOutputFactory; -import com.vladsch.flexmark.formatter.Formatter; -import com.vladsch.flexmark.html2md.converter.FlexmarkHtmlConverter; -import com.vladsch.flexmark.parser.Parser; -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.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.InsertAnchorNode; -import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.InsertVisitor; -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.util.ObjectUtils; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.codehaus.stax2.XMLOutputFactory2; -import org.codehaus.stax2.XMLStreamWriter2; -import org.codehaus.stax2.evt.XMLEventFactory2; -import org.jsoup.Jsoup; -import org.jsoup.nodes.TextNode; -import org.jsoup.select.NodeTraversor; -import org.jsoup.select.NodeVisitor; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.function.Predicate; -import java.util.regex.Pattern; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - -import javax.xml.stream.XMLEventWriter; -import javax.xml.stream.XMLOutputFactory; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamWriter; - -import edu.umd.cs.findbugs.annotations.NonNull; -import edu.umd.cs.findbugs.annotations.Nullable; - -@SuppressWarnings("PMD.CouplingBetweenObjects") -public abstract class AbstractMarkupString> - implements IMarkupString { - private static final Logger LOGGER = LogManager.getLogger(FlexmarkFactory.class); - - private static final Pattern QUOTE_TAG_REPLACEMENT_PATTERN - = Pattern.compile(""); - - // - // @NonNull - // private static final String DEFAULT_HTML_NS = "http://www.w3.org/1999/xhtml"; - // @NonNull - // private static final String DEFAULT_HTML_PREFIX = ""; - - @NonNull - private final Document document; - - /** - * Construct a new markup string based on the provided flexmark AST graph. - * - * @param document - * the AST graph representing Markdown text - */ - protected AbstractMarkupString(@NonNull Document document) { - this.document = document; - } - - @Override - public Document getDocument() { - return document; - } - - @Override - public boolean isEmpty() { - return getDocument().getFirstChild() == null; - } - - /** - * Parse HTML-based text into markdown as a flexmark AST graph. - *

- * This method uses a two-step approach that first translates the HTML into - * markdown, and then parses the markdown into an AST graph. - * - * @param html - * the HTML text to parse - * @param htmlParser - * the HTML parser used to produce markdown - * @param markdownParser - * the markdown parser - * @return the markdown AST graph - */ - @NonNull - protected static Document parseHtml(@NonNull String html, @NonNull FlexmarkHtmlConverter htmlParser, - @NonNull Parser markdownParser) { - org.jsoup.nodes.Document document = Jsoup.parse(html); - - // Fix for usnistgov/liboscal-java#5 - // Caused by not stripping out extra newlines inside HTML tags - NodeTraversor.traverse(new NodeVisitor() { - - @Override - public void head(org.jsoup.nodes.Node node, int depth) { - if (node instanceof TextNode) { - TextNode textNode = (TextNode) node; - - org.jsoup.nodes.Node parent = textNode.parent(); - - if (!isTag(parent, "code") || !isTag(parent.parent(), "pre")) { - node.replaceWith(new TextNode(textNode.text())); - } - } - } - - private boolean isTag(@Nullable org.jsoup.nodes.Node node, @NonNull String tagName) { - return node != null && tagName.equals(node.normalName()); - } - - }, document); - - String markdown = htmlParser.convert(document); - assert markdown != null; - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("html->markdown: {}", markdown); - } - return parseMarkdown(markdown, markdownParser); - } - - /** - * Parse markdown-based text into a flexmark AST graph. - * - * @param markdown - * the markdown text to parse - * @param parser - * the markdown parser - * @return the markdown AST graph - */ - @SuppressWarnings("null") - @NonNull - protected static Document parseMarkdown(@NonNull String markdown, @NonNull Parser parser) { - return parser.parse(markdown); - } - - @Override - public String toXHtml(@NonNull String namespace) throws XMLStreamException, IOException { - - String retval; - - Document document = getDocument(); - if (document.hasChildren()) { - - XMLOutputFactory2 factory = (XMLOutputFactory2) XMLOutputFactory.newInstance(); - assert factory instanceof WstxOutputFactory; - factory.setProperty(WstxOutputProperties.P_OUTPUT_VALIDATE_STRUCTURE, false); - try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { - XMLStreamWriter2 xmlStreamWriter = (XMLStreamWriter2) factory.createXMLStreamWriter(os); - - writeXHtml(namespace, ObjectUtils.notNull(xmlStreamWriter)); - - xmlStreamWriter.flush(); - xmlStreamWriter.close(); - os.flush(); - retval = ObjectUtils.notNull(os.toString(StandardCharsets.UTF_8)); - } - } else { - retval = ""; - } - return retval; - } - - @Override - public String toHtml() { - // String html; - // try { - // html = toXHtml(""); - // } catch(RuntimeException ex) { - // throw ex; - // } catch (Throwable ex) { - // throw new RuntimeException(ex); - // } - // return QUOTE_TAG_REPLACEMENT_PATTERN.matcher(html) - // .replaceAll("""); - String html = getFlexmarkFactory().getHtmlRenderer().render(getDocument()); - return ObjectUtils.notNull(QUOTE_TAG_REPLACEMENT_PATTERN.matcher(html) - .replaceAll(""")); - } - - @Override - public String toMarkdown() { - return toMarkdown(getFlexmarkFactory().getFormatter()); - } - - @Override - public String toMarkdown(Formatter formatter) { - return ObjectUtils.notNull(formatter.render(getDocument())); - } - - @Override - public void writeXHtml(String namespace, XMLStreamWriter2 streamWriter) throws XMLStreamException { - Document document = getDocument(); - if (document.hasChildren()) { - IMarkupWriter writer = new MarkupXmlStreamWriter( - namespace, - getFlexmarkFactory().getListOptions(), - streamWriter); - - IMarkupVisitor visitor = new MarkupVisitor<>(isBlock()); - visitor.visitDocument(document, writer); - } else { - streamWriter.writeCharacters(""); - } - } - - @Override - public void writeXHtml(String namespace, XMLEventFactory2 eventFactory, XMLEventWriter eventWriter) - throws XMLStreamException { - Document document = getDocument(); - if (document.hasChildren()) { - - IMarkupWriter writer = new MarkupXmlEventWriter( - namespace, - getFlexmarkFactory().getListOptions(), - eventWriter, - eventFactory); - - IMarkupVisitor visitor = new MarkupVisitor<>(isBlock()); - visitor.visitDocument(getDocument(), writer); - } else { - eventWriter.add(eventFactory.createSpace("")); - } - - } - - @SuppressWarnings("null") - @Override - public Stream getNodesAsStream() { - return Stream.concat(Stream.of(getDocument()), - StreamSupport.stream(getDocument().getDescendants().spliterator(), false)); - } - - @Override - @NonNull - public List getInserts() { - return getInserts(insert -> true); - } - - /** - * Retrieve all insert statements that are contained within this markup text - * that match the provided filter. - * - * @param filter - * a filter used to identify matching insert statements - * @return the matching insert statements - */ - @Override - @NonNull - public List getInserts(@NonNull Predicate filter) { - InsertVisitor visitor = new InsertVisitor(filter); - visitor.visitChildren(getDocument()); - return visitor.getInserts(); - } - - @Override - public String toString() { - return AstCollectingVisitor.asString(getDocument()); - } -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.datatype.markup; + +import com.ctc.wstx.api.WstxOutputProperties; +import com.ctc.wstx.stax.WstxOutputFactory; +import com.vladsch.flexmark.formatter.Formatter; +import com.vladsch.flexmark.html2md.converter.FlexmarkHtmlConverter; +import com.vladsch.flexmark.parser.Parser; +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.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.InsertAnchorNode; +import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.InsertVisitor; +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.util.ObjectUtils; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.codehaus.stax2.XMLOutputFactory2; +import org.codehaus.stax2.XMLStreamWriter2; +import org.codehaus.stax2.evt.XMLEventFactory2; +import org.jsoup.Jsoup; +import org.jsoup.nodes.TextNode; +import org.jsoup.select.NodeTraversor; +import org.jsoup.select.NodeVisitor; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.function.Predicate; +import java.util.regex.Pattern; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; + +@SuppressWarnings("PMD.CouplingBetweenObjects") +public abstract class AbstractMarkupString> + implements IMarkupString { + private static final Logger LOGGER = LogManager.getLogger(FlexmarkFactory.class); + + private static final Pattern QUOTE_TAG_REPLACEMENT_PATTERN + = Pattern.compile(""); + + // + // @NonNull + // private static final String DEFAULT_HTML_NS = "http://www.w3.org/1999/xhtml"; + // @NonNull + // private static final String DEFAULT_HTML_PREFIX = ""; + + @NonNull + private final Document document; + + /** + * Construct a new markup string based on the provided flexmark AST graph. + * + * @param document + * the AST graph representing Markdown text + */ + protected AbstractMarkupString(@NonNull Document document) { + this.document = document; + } + + @Override + public Document getDocument() { + return document; + } + + @Override + public boolean isEmpty() { + return getDocument().getFirstChild() == null; + } + + /** + * Parse HTML-based text into markdown as a flexmark AST graph. + *

+ * This method uses a two-step approach that first translates the HTML into + * markdown, and then parses the markdown into an AST graph. + * + * @param html + * the HTML text to parse + * @param htmlParser + * the HTML parser used to produce markdown + * @param markdownParser + * the markdown parser + * @return the markdown AST graph + */ + @NonNull + protected static Document parseHtml(@NonNull String html, @NonNull FlexmarkHtmlConverter htmlParser, + @NonNull Parser markdownParser) { + org.jsoup.nodes.Document document = Jsoup.parse(html); + + // Fix for usnistgov/liboscal-java#5 + // Caused by not stripping out extra newlines inside HTML tags + NodeTraversor.traverse(new NodeVisitor() { + + @Override + public void head(org.jsoup.nodes.Node node, int depth) { + if (node instanceof TextNode) { + TextNode textNode = (TextNode) node; + + org.jsoup.nodes.Node parent = textNode.parent(); + + if (!isTag(parent, "code") || !isTag(parent.parent(), "pre")) { + node.replaceWith(new TextNode(textNode.text())); + } + } + } + + private boolean isTag(@Nullable org.jsoup.nodes.Node node, @NonNull String tagName) { + return node != null && tagName.equals(node.normalName()); + } + + }, document); + + String markdown = htmlParser.convert(document); + assert markdown != null; + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("html->markdown: {}", markdown); + } + return parseMarkdown(markdown, markdownParser); + } + + /** + * Parse markdown-based text into a flexmark AST graph. + * + * @param markdown + * the markdown text to parse + * @param parser + * the markdown parser + * @return the markdown AST graph + */ + @SuppressWarnings("null") + @NonNull + protected static Document parseMarkdown(@NonNull String markdown, @NonNull Parser parser) { + return parser.parse(markdown); + } + + @Override + public String toXHtml(@NonNull String namespace) throws XMLStreamException, IOException { + + String retval; + + Document document = getDocument(); + if (document.hasChildren()) { + + XMLOutputFactory2 factory = (XMLOutputFactory2) XMLOutputFactory.newInstance(); + assert factory instanceof WstxOutputFactory; + factory.setProperty(WstxOutputProperties.P_OUTPUT_VALIDATE_STRUCTURE, false); + try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { + XMLStreamWriter2 xmlStreamWriter = (XMLStreamWriter2) factory.createXMLStreamWriter(os); + + writeXHtml(namespace, ObjectUtils.notNull(xmlStreamWriter)); + + xmlStreamWriter.flush(); + xmlStreamWriter.close(); + os.flush(); + retval = ObjectUtils.notNull(os.toString(StandardCharsets.UTF_8)); + } + } else { + retval = ""; + } + return retval; + } + + @Override + public String toHtml() { + // String html; + // try { + // html = toXHtml(""); + // } catch(RuntimeException ex) { + // throw ex; + // } catch (Throwable ex) { + // throw new RuntimeException(ex); + // } + // return QUOTE_TAG_REPLACEMENT_PATTERN.matcher(html) + // .replaceAll("""); + String html = getFlexmarkFactory().getHtmlRenderer().render(getDocument()); + return ObjectUtils.notNull(QUOTE_TAG_REPLACEMENT_PATTERN.matcher(html) + .replaceAll(""")); + } + + @Override + public String toMarkdown() { + return toMarkdown(getFlexmarkFactory().getFormatter()); + } + + @Override + public String toMarkdown(Formatter formatter) { + return ObjectUtils.notNull(formatter.render(getDocument())); + } + + @Override + public void writeXHtml(String namespace, XMLStreamWriter2 streamWriter) throws XMLStreamException { + Document document = getDocument(); + if (document.hasChildren()) { + IMarkupWriter writer = new MarkupXmlStreamWriter( + namespace, + getFlexmarkFactory().getListOptions(), + streamWriter); + + IMarkupVisitor visitor = new MarkupVisitor<>(isBlock()); + visitor.visitDocument(document, writer); + } else { + streamWriter.writeCharacters(""); + } + } + + @Override + public void writeXHtml(String namespace, XMLEventFactory2 eventFactory, XMLEventWriter eventWriter) + throws XMLStreamException { + Document document = getDocument(); + if (document.hasChildren()) { + + IMarkupWriter writer = new MarkupXmlEventWriter( + namespace, + getFlexmarkFactory().getListOptions(), + eventWriter, + eventFactory); + + IMarkupVisitor visitor = new MarkupVisitor<>(isBlock()); + visitor.visitDocument(getDocument(), writer); + } else { + eventWriter.add(eventFactory.createSpace("")); + } + + } + + @SuppressWarnings("null") + @Override + public Stream getNodesAsStream() { + return Stream.concat(Stream.of(getDocument()), + StreamSupport.stream(getDocument().getDescendants().spliterator(), false)); + } + + @Override + @NonNull + public List getInserts() { + return getInserts(insert -> true); + } + + /** + * Retrieve all insert statements that are contained within this markup text + * that match the provided filter. + * + * @param filter + * a filter used to identify matching insert statements + * @return the matching insert statements + */ + @Override + @NonNull + public List getInserts(@NonNull Predicate filter) { + InsertVisitor visitor = new InsertVisitor(filter); + visitor.visitChildren(getDocument()); + return visitor.getInserts(); + } + + @Override + public String toString() { + return AstCollectingVisitor.asString(getDocument()); + } +} 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 20772f991..196b5f303 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 @@ -1,110 +1,110 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype.markup; - -import com.vladsch.flexmark.html.HtmlRenderer; -import com.vladsch.flexmark.parser.Parser; -import com.vladsch.flexmark.util.ast.Block; -import com.vladsch.flexmark.util.ast.Document; -import com.vladsch.flexmark.util.ast.Node; -import com.vladsch.flexmark.util.data.DataSet; -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 java.util.Collection; -import java.util.LinkedList; -import java.util.List; - -import edu.umd.cs.findbugs.annotations.NonNull; - -public class MarkupLine - extends AbstractMarkupString { - - @NonNull - private static final DataSet FLEXMARK_CONFIG = newParserOptions(); - - @NonNull - private static final FlexmarkFactory FLEXMARK_FACTORY = FlexmarkFactory.newInstance(FLEXMARK_CONFIG); - - @SuppressWarnings("null") - @NonNull - protected static DataSet newParserOptions() { - MutableDataSet options = new MutableDataSet(); - // disable inline HTML - options.set(Parser.HTML_BLOCK_PARSER, false); - // disable list processing - options.set(Parser.LIST_BLOCK_PARSER, false); - options.set(HtmlRenderer.SUPPRESS_HTML_BLOCKS, true); - - Collection currentExtensions = Parser.EXTENSIONS.get(FlexmarkConfiguration.FLEXMARK_CONFIG); - List extensions = new LinkedList<>(currentExtensions); - extensions.add(SuppressPTagExtension.create()); - Parser.EXTENSIONS.set(options, extensions); - - return FlexmarkConfiguration.newFlexmarkConfig(options); - } - - @NonNull - public static MarkupLine fromHtml(@NonNull String html) { - return new MarkupLine( - parseHtml(html, FLEXMARK_FACTORY.getFlexmarkHtmlConverter(), FLEXMARK_FACTORY.getMarkdownParser())); - } - - @NonNull - public static MarkupLine fromMarkdown(@NonNull String markdown) { - return new MarkupLine(parseMarkdown(markdown, FLEXMARK_FACTORY.getMarkdownParser())); - } - - @Override - public FlexmarkFactory getFlexmarkFactory() { - return FLEXMARK_FACTORY; - } - - protected MarkupLine(@NonNull Document astNode) { - super(astNode); - Node child = astNode.getFirstChild(); - if (child instanceof Block && child.getNext() != null) { - throw new IllegalStateException("multiple blocks not allowed"); - } // else empty markdown - } - - @Override - public MarkupLine copy() { - // TODO: find a way to do a deep copy - // this is a shallow copy that uses the same underlying Document object - return new MarkupLine(getDocument()); - } - - @Override - public boolean isBlock() { - return false; - } -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.datatype.markup; + +import com.vladsch.flexmark.html.HtmlRenderer; +import com.vladsch.flexmark.parser.Parser; +import com.vladsch.flexmark.util.ast.Block; +import com.vladsch.flexmark.util.ast.Document; +import com.vladsch.flexmark.util.ast.Node; +import com.vladsch.flexmark.util.data.DataSet; +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 java.util.Collection; +import java.util.LinkedList; +import java.util.List; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public final class MarkupLine + extends AbstractMarkupString { + + @NonNull + private static final DataSet FLEXMARK_CONFIG = newParserOptions(); + + @NonNull + private static final FlexmarkFactory FLEXMARK_FACTORY = FlexmarkFactory.newInstance(FLEXMARK_CONFIG); + + @SuppressWarnings("null") + @NonNull + protected static DataSet newParserOptions() { + MutableDataSet options = new MutableDataSet(); + // disable inline HTML + options.set(Parser.HTML_BLOCK_PARSER, false); + // disable list processing + options.set(Parser.LIST_BLOCK_PARSER, false); + options.set(HtmlRenderer.SUPPRESS_HTML_BLOCKS, true); + + Collection currentExtensions = Parser.EXTENSIONS.get(FlexmarkConfiguration.FLEXMARK_CONFIG); + List extensions = new LinkedList<>(currentExtensions); + extensions.add(SuppressPTagExtension.create()); + Parser.EXTENSIONS.set(options, extensions); + + return FlexmarkConfiguration.newFlexmarkConfig(options); + } + + @NonNull + public static MarkupLine fromHtml(@NonNull String html) { + return new MarkupLine( + parseHtml(html, FLEXMARK_FACTORY.getFlexmarkHtmlConverter(), FLEXMARK_FACTORY.getMarkdownParser())); + } + + @NonNull + public static MarkupLine fromMarkdown(@NonNull String markdown) { + return new MarkupLine(parseMarkdown(markdown, FLEXMARK_FACTORY.getMarkdownParser())); + } + + @Override + public FlexmarkFactory getFlexmarkFactory() { + return FLEXMARK_FACTORY; + } + + protected MarkupLine(@NonNull Document astNode) { + super(astNode); + Node child = astNode.getFirstChild(); + if (child instanceof Block && child.getNext() != null) { + throw new IllegalStateException("multiple blocks not allowed"); + } // else empty markdown + } + + @Override + public MarkupLine copy() { + // TODO: find a way to do a deep copy + // this is a shallow copy that uses the same underlying Document object + return new MarkupLine(getDocument()); + } + + @Override + public boolean isBlock() { + return false; + } +} 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 b1dbdd58b..0e3d0b31a 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 @@ -1,100 +1,102 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype.markup; - -import com.fasterxml.jackson.core.JsonParser; - -import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.XmlMarkupParser; -import gov.nist.secauto.metaschema.core.metapath.item.atomic.IMarkupItem; -import gov.nist.secauto.metaschema.core.util.ObjectUtils; - -import org.codehaus.stax2.XMLEventReader2; - -import java.io.IOException; -import java.util.List; - -import javax.xml.stream.XMLStreamException; - -import edu.umd.cs.findbugs.annotations.NonNull; - -public class MarkupLineAdapter - extends AbstractMarkupAdapter { - @NonNull - private static final List NAMES = ObjectUtils.notNull( - List.of("markup-line")); - - MarkupLineAdapter() { - super(MarkupLine.class); - } - - @Override - public List getNames() { - return NAMES; - } - - /** - * Parse a line of Markdown. - */ - @Override - public MarkupLine parse(String value) { - return MarkupLine.fromMarkdown(value); - } - - @SuppressWarnings("null") - @Override - public MarkupLine parse(XMLEventReader2 eventReader) throws IOException { - try { - return XmlMarkupParser.instance().parseMarkupline(eventReader); - } catch (XMLStreamException ex) { - throw new IOException(ex); - } - } - - @Override - public MarkupLine parse(JsonParser parser) throws IOException { - @SuppressWarnings("null") MarkupLine retval = parse(parser.getValueAsString()); - // skip past value - parser.nextToken(); - return retval; - } - - @Override - public String getDefaultJsonValueKey() { - return "RICHTEXT"; - } - - @Override - public Class getItemClass() { - return IMarkupItem.class; - } - - @Override - public IMarkupItem newItem(Object value) { - MarkupLine item = toValue(value); - return IMarkupItem.valueOf(item); - } -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.datatype.markup; + +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; + +import org.codehaus.stax2.XMLEventReader2; + +import java.io.IOException; +import java.util.List; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class MarkupLineAdapter + extends AbstractMarkupAdapter { + @NonNull + private static final List NAMES = ObjectUtils.notNull( + List.of(new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "markup-line"))); + + MarkupLineAdapter() { + super(MarkupLine.class); + } + + @Override + public List getNames() { + return NAMES; + } + + /** + * Parse a line of Markdown. + */ + @Override + public MarkupLine parse(String value) { + return MarkupLine.fromMarkdown(value); + } + + @SuppressWarnings("null") + @Override + public MarkupLine parse(XMLEventReader2 eventReader) throws IOException { + try { + return XmlMarkupParser.instance().parseMarkupline(eventReader); + } catch (XMLStreamException ex) { + throw new IOException(ex); + } + } + + @Override + public MarkupLine parse(JsonParser parser) throws IOException { + @SuppressWarnings("null") MarkupLine retval = parse(parser.getValueAsString()); + // skip past value + parser.nextToken(); + return retval; + } + + @Override + public String getDefaultJsonValueKey() { + return "RICHTEXT"; + } + + @Override + public Class getItemClass() { + return IMarkupItem.class; + } + + @Override + public IMarkupItem newItem(Object value) { + MarkupLine item = toValue(value); + return IMarkupItem.valueOf(item); + } +} 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 205b0ff35..534621a1c 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 @@ -1,96 +1,96 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype.markup; - -import com.vladsch.flexmark.util.ast.Document; - -import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.FlexmarkFactory; - -import edu.umd.cs.findbugs.annotations.NonNull; - -public class MarkupMultiline - extends AbstractMarkupString { - - @NonNull - private static final FlexmarkFactory FLEXMARK_FACTORY = FlexmarkFactory.instance(); - - /** - * Convert the provided HTML string into markup. - * - * @param html - * the HTML - * @return the multiline markup instance - */ - @NonNull - public static MarkupMultiline fromHtml(@NonNull String html) { - return new MarkupMultiline( - parseHtml( - html, - FLEXMARK_FACTORY.getFlexmarkHtmlConverter(), - FLEXMARK_FACTORY.getMarkdownParser())); - } - - /** - * Convert the provided markdown string into markup. - * - * @param markdown - * the markup - * @return the multiline markup instance - */ - @NonNull - public static MarkupMultiline fromMarkdown(@NonNull String markdown) { - return new MarkupMultiline( - parseMarkdown(markdown, FLEXMARK_FACTORY.getMarkdownParser())); - } - - /** - * Construct a new multiline markup instance. - * - * @param astNode - * the parsed markup AST - */ - public MarkupMultiline(@NonNull Document astNode) { - super(astNode); - } - - @Override - public FlexmarkFactory getFlexmarkFactory() { - return FLEXMARK_FACTORY; - } - - @Override - public MarkupMultiline copy() { - // TODO: find a way to do a deep copy - // this is a shallow copy that uses the same underlying Document object - return new MarkupMultiline(getDocument()); - } - - @Override - public boolean isBlock() { - return true; - } -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.datatype.markup; + +import com.vladsch.flexmark.util.ast.Document; + +import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.FlexmarkFactory; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class MarkupMultiline + extends AbstractMarkupString { + + @NonNull + private static final FlexmarkFactory FLEXMARK_FACTORY = FlexmarkFactory.instance(); + + /** + * Convert the provided HTML string into markup. + * + * @param html + * the HTML + * @return the multiline markup instance + */ + @NonNull + public static MarkupMultiline fromHtml(@NonNull String html) { + return new MarkupMultiline( + parseHtml( + html, + FLEXMARK_FACTORY.getFlexmarkHtmlConverter(), + FLEXMARK_FACTORY.getMarkdownParser())); + } + + /** + * Convert the provided markdown string into markup. + * + * @param markdown + * the markup + * @return the multiline markup instance + */ + @NonNull + public static MarkupMultiline fromMarkdown(@NonNull String markdown) { + return new MarkupMultiline( + parseMarkdown(markdown, FLEXMARK_FACTORY.getMarkdownParser())); + } + + /** + * Construct a new multiline markup instance. + * + * @param astNode + * the parsed markup AST + */ + public MarkupMultiline(@NonNull Document astNode) { + super(astNode); + } + + @Override + public FlexmarkFactory getFlexmarkFactory() { + return FLEXMARK_FACTORY; + } + + @Override + public MarkupMultiline copy() { + // TODO: find a way to do a deep copy + // this is a shallow copy that uses the same underlying Document object + return new MarkupMultiline(getDocument()); + } + + @Override + public boolean isBlock() { + return true; + } +} 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 3c907fa90..fee505840 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 @@ -1,111 +1,112 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype.markup; - -import com.fasterxml.jackson.core.JsonParser; - -import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.XmlMarkupParser; -import gov.nist.secauto.metaschema.core.metapath.item.atomic.IMarkupItem; -import gov.nist.secauto.metaschema.core.util.ObjectUtils; - -import org.codehaus.stax2.XMLEventReader2; - -import java.io.IOException; -import java.util.List; - -import javax.xml.namespace.QName; -import javax.xml.stream.XMLStreamException; - -import edu.umd.cs.findbugs.annotations.NonNull; - -public class MarkupMultilineAdapter - extends AbstractMarkupAdapter { - @NonNull - private static final List NAMES = ObjectUtils.notNull( - List.of("markup-multiline")); - - MarkupMultilineAdapter() { - super(MarkupMultiline.class); - } - - @Override - public List getNames() { - return NAMES; - } - - @Override - public boolean isUnrappedValueAllowedInXml() { - return true; - } - - /** - * Parse a line of Markdown. - */ - @Override - public MarkupMultiline parse(String value) { - return MarkupMultiline.fromMarkdown(value); - } - - @SuppressWarnings("null") - @Override - public MarkupMultiline parse(XMLEventReader2 eventReader) throws IOException { - try { - return XmlMarkupParser.instance().parseMarkupMultiline(eventReader); - } catch (XMLStreamException ex) { - throw new IOException(ex); - } - } - - @Override - public MarkupMultiline parse(JsonParser parser) throws IOException { - @SuppressWarnings("null") MarkupMultiline retval = parse(parser.getValueAsString()); - // skip past value - parser.nextToken(); - return retval; - } - - @Override - public boolean canHandleQName(QName nextQName) { - return true; - } - - @Override - public String getDefaultJsonValueKey() { - return "PROSE"; - } - - @Override - public Class getItemClass() { - return IMarkupItem.class; - } - - @Override - public IMarkupItem newItem(Object value) { - MarkupMultiline item = toValue(value); - return IMarkupItem.valueOf(item); - } -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.datatype.markup; + +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; + +import org.codehaus.stax2.XMLEventReader2; + +import java.io.IOException; +import java.util.List; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class MarkupMultilineAdapter + extends AbstractMarkupAdapter { + @NonNull + private static final List NAMES = ObjectUtils.notNull( + List.of(new QName(MetapathConstants.NS_METAPATH.toASCIIString(), "markup-multiline"))); + + MarkupMultilineAdapter() { + super(MarkupMultiline.class); + } + + @Override + public List getNames() { + return NAMES; + } + + @Override + public boolean isUnrappedValueAllowedInXml() { + return true; + } + + /** + * Parse a line of Markdown. + */ + @Override + public MarkupMultiline parse(String value) { + return MarkupMultiline.fromMarkdown(value); + } + + @SuppressWarnings("null") + @Override + public MarkupMultiline parse(XMLEventReader2 eventReader) throws IOException { + try { + return XmlMarkupParser.instance().parseMarkupMultiline(eventReader); + } catch (XMLStreamException ex) { + throw new IOException(ex); + } + } + + @Override + public MarkupMultiline parse(JsonParser parser) throws IOException { + @SuppressWarnings("null") MarkupMultiline retval = parse(parser.getValueAsString()); + // skip past value + parser.nextToken(); + return retval; + } + + @Override + public boolean canHandleQName(QName nextQName) { + return true; + } + + @Override + public String getDefaultJsonValueKey() { + return "PROSE"; + } + + @Override + public Class getItemClass() { + return IMarkupItem.class; + } + + @Override + public IMarkupItem newItem(Object value) { + MarkupMultiline item = toValue(value); + return IMarkupItem.valueOf(item); + } +} 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/AstCollectingVisitor.java index 2d51a98e2..be57b01bc 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/AstCollectingVisitor.java @@ -1,88 +1,88 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype.markup.flexmark; - -import com.vladsch.flexmark.util.ast.Node; -import com.vladsch.flexmark.util.ast.NodeVisitorBase; - -import gov.nist.secauto.metaschema.core.util.ObjectUtils; - -import edu.umd.cs.findbugs.annotations.NonNull; - -public final class AstCollectingVisitor - extends NodeVisitorBase { - public static final String EOL = "\n"; - - @SuppressWarnings("PMD.AvoidStringBufferField") // short lived - private final StringBuilder strBuilder; - private int indent; // 0; - - private AstCollectingVisitor(@NonNull StringBuilder strBuilder) { - this.strBuilder = strBuilder; - indent = 0; - } - - /** - * Generate a string representation of an AST. - * - * @param node - * the branch of the tree to visualize - * @return the string representation of the AST. - */ - @NonNull - public static String asString(@NonNull Node node) { - StringBuilder builder = new StringBuilder(); - AstCollectingVisitor visitor = new AstCollectingVisitor(builder); - visitor.collect(node); - return ObjectUtils.notNull(builder.toString()); - } - - private void appendIndent() { - for (int i = 0; i < indent * 2; i++) { - strBuilder.append(' '); - } - } - - private void collect(@NonNull Node node) { - visit(node); - } - - @Override - protected void visit(Node node) { - assert node != null; - appendIndent(); - node.astString(strBuilder, true); - strBuilder.append(EOL); - indent++; - - try { - super.visitChildren(node); - } finally { - indent--; - } - } -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.datatype.markup.flexmark; + +import com.vladsch.flexmark.util.ast.Node; +import com.vladsch.flexmark.util.ast.NodeVisitorBase; + +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public final class AstCollectingVisitor + extends NodeVisitorBase { + public static final String EOL = "\n"; + + @SuppressWarnings("PMD.AvoidStringBufferField") // short lived + private final StringBuilder strBuilder; + private int indent; // 0; + + private AstCollectingVisitor(@NonNull StringBuilder strBuilder) { + this.strBuilder = strBuilder; + indent = 0; + } + + /** + * Generate a string representation of an AST. + * + * @param node + * the branch of the tree to visualize + * @return the string representation of the AST. + */ + @NonNull + public static String asString(@NonNull Node node) { + StringBuilder builder = new StringBuilder(); + AstCollectingVisitor visitor = new AstCollectingVisitor(builder); + visitor.collect(node); + return ObjectUtils.notNull(builder.toString()); + } + + private void appendIndent() { + for (int i = 0; i < indent * 2; i++) { + strBuilder.append(' '); + } + } + + private void collect(@NonNull Node node) { + visit(node); + } + + @Override + protected void visit(Node node) { + assert node != null; + appendIndent(); + node.astString(strBuilder, true); + strBuilder.append(EOL); + indent++; + + try { + super.visitChildren(node); + } finally { + indent--; + } + } +} 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 c48378817..01b3ddbc2 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 @@ -1,103 +1,103 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype.markup.flexmark; - -import com.vladsch.flexmark.formatter.Formatter; -import com.vladsch.flexmark.html.HtmlRenderer; -import com.vladsch.flexmark.html2md.converter.FlexmarkHtmlConverter; -import com.vladsch.flexmark.parser.ListOptions; -import com.vladsch.flexmark.parser.Parser; -import com.vladsch.flexmark.util.data.DataHolder; - -import edu.umd.cs.findbugs.annotations.NonNull; - -@SuppressWarnings("PMD.DataClass") -public final class FlexmarkFactory { - @NonNull - private static final FlexmarkFactory SINGLETON = new FlexmarkFactory(); - @NonNull - private final Parser markdownParser; - @NonNull - private final HtmlRenderer htmlRenderer; - @NonNull - private final Formatter formatter; - @NonNull - private final FlexmarkHtmlConverter htmlConverter; - @NonNull - final ListOptions listOptions; - - @SuppressWarnings("PMD.AvoidSynchronizedAtMethodLevel") - @NonNull - public static synchronized FlexmarkFactory instance() { - return SINGLETON; - } - - @NonNull - public static FlexmarkFactory newInstance(@NonNull DataHolder config) { - return new FlexmarkFactory(config); - } - - private FlexmarkFactory() { - this(FlexmarkConfiguration.FLEXMARK_CONFIG); - } - - @SuppressWarnings("null") - private FlexmarkFactory(@NonNull DataHolder config) { - this.markdownParser = Parser.builder(config) - .customDelimiterProcessor(new FixedEmphasisDelimiterProcessor(Parser.STRONG_WRAPS_EMPHASIS.get(config))) - .build(); - this.htmlRenderer = HtmlRenderer.builder(config).build(); - this.formatter = Formatter.builder(config).build(); - this.htmlConverter = FlexmarkHtmlConverter.builder(config).build(); - this.listOptions = ListOptions.get(config); - } - - @NonNull - public ListOptions getListOptions() { - return listOptions; - } - - @NonNull - public Parser getMarkdownParser() { - return markdownParser; - } - - @NonNull - public HtmlRenderer getHtmlRenderer() { - return htmlRenderer; - } - - @NonNull - public Formatter getFormatter() { - return formatter; - } - - @NonNull - public FlexmarkHtmlConverter getFlexmarkHtmlConverter() { - return htmlConverter; - } -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.datatype.markup.flexmark; + +import com.vladsch.flexmark.formatter.Formatter; +import com.vladsch.flexmark.html.HtmlRenderer; +import com.vladsch.flexmark.html2md.converter.FlexmarkHtmlConverter; +import com.vladsch.flexmark.parser.ListOptions; +import com.vladsch.flexmark.parser.Parser; +import com.vladsch.flexmark.util.data.DataHolder; + +import edu.umd.cs.findbugs.annotations.NonNull; + +@SuppressWarnings("PMD.DataClass") +public final class FlexmarkFactory { + @NonNull + private static final FlexmarkFactory SINGLETON = new FlexmarkFactory(); + @NonNull + private final Parser markdownParser; + @NonNull + private final HtmlRenderer htmlRenderer; + @NonNull + private final Formatter formatter; + @NonNull + private final FlexmarkHtmlConverter htmlConverter; + @NonNull + final ListOptions listOptions; + + @SuppressWarnings("PMD.AvoidSynchronizedAtMethodLevel") + @NonNull + public static synchronized FlexmarkFactory instance() { + return SINGLETON; + } + + @NonNull + public static FlexmarkFactory newInstance(@NonNull DataHolder config) { + return new FlexmarkFactory(config); + } + + private FlexmarkFactory() { + this(FlexmarkConfiguration.FLEXMARK_CONFIG); + } + + @SuppressWarnings("null") + private FlexmarkFactory(@NonNull DataHolder config) { + this.markdownParser = Parser.builder(config) + .customDelimiterProcessor(new FixedEmphasisDelimiterProcessor(Parser.STRONG_WRAPS_EMPHASIS.get(config))) + .build(); + this.htmlRenderer = HtmlRenderer.builder(config).build(); + this.formatter = Formatter.builder(config).build(); + this.htmlConverter = FlexmarkHtmlConverter.builder(config).build(); + this.listOptions = ListOptions.get(config); + } + + @NonNull + public ListOptions getListOptions() { + return listOptions; + } + + @NonNull + public Parser getMarkdownParser() { + return markdownParser; + } + + @NonNull + public HtmlRenderer getHtmlRenderer() { + return htmlRenderer; + } + + @NonNull + public Formatter getFormatter() { + return formatter; + } + + @NonNull + public FlexmarkHtmlConverter getFlexmarkHtmlConverter() { + return htmlConverter; + } +} 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 e5cc2434a..894eb506f 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 @@ -172,6 +172,7 @@ public HtmlNodeRenderer apply(DataHolder options) { public static class DoubleQuoteNode extends TypographicQuotes { + @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 8300faa5a..36e422b17 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 @@ -1,348 +1,348 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype.markup.flexmark; // NOPMD AST processor - -import com.vladsch.flexmark.formatter.Formatter; -import com.vladsch.flexmark.formatter.MarkdownWriter; -import com.vladsch.flexmark.formatter.NodeFormatter; -import com.vladsch.flexmark.formatter.NodeFormatterContext; -import com.vladsch.flexmark.formatter.NodeFormatterFactory; -import com.vladsch.flexmark.formatter.NodeFormattingHandler; -import com.vladsch.flexmark.html.HtmlRenderer; -import com.vladsch.flexmark.html.HtmlWriter; -import com.vladsch.flexmark.html.renderer.NodeRenderer; -import com.vladsch.flexmark.html.renderer.NodeRendererContext; -import com.vladsch.flexmark.html.renderer.NodeRendererFactory; -import com.vladsch.flexmark.html.renderer.NodeRenderingHandler; -import com.vladsch.flexmark.html2md.converter.FlexmarkHtmlConverter; -import com.vladsch.flexmark.html2md.converter.HtmlMarkdownWriter; -import com.vladsch.flexmark.html2md.converter.HtmlNodeConverterContext; -import com.vladsch.flexmark.html2md.converter.HtmlNodeRenderer; -import com.vladsch.flexmark.html2md.converter.HtmlNodeRendererFactory; -import com.vladsch.flexmark.html2md.converter.HtmlNodeRendererHandler; -import com.vladsch.flexmark.parser.InlineParser; -import com.vladsch.flexmark.parser.InlineParserExtension; -import com.vladsch.flexmark.parser.InlineParserExtensionFactory; -import com.vladsch.flexmark.parser.LightInlineParser; -import com.vladsch.flexmark.parser.Parser; -import com.vladsch.flexmark.util.ast.Node; -import com.vladsch.flexmark.util.data.DataHolder; -import com.vladsch.flexmark.util.data.DataKey; -import com.vladsch.flexmark.util.data.MutableDataHolder; -import com.vladsch.flexmark.util.misc.Extension; -import com.vladsch.flexmark.util.sequence.BasedSequence; -import com.vladsch.flexmark.util.sequence.CharSubSequence; - -import org.jsoup.nodes.Element; - -import java.util.Collections; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import edu.umd.cs.findbugs.annotations.NonNull; - -public class InsertAnchorExtension - implements Parser.ParserExtension, HtmlRenderer.HtmlRendererExtension, - Formatter.FormatterExtension, FlexmarkHtmlConverter.HtmlConverterExtension { - public 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); - - public static Extension create() { - return new InsertAnchorExtension(); - } - - @Override - public void parserOptions(MutableDataHolder options) { - // do nothing - } - - @Override - public void rendererOptions(MutableDataHolder options) { - // do nothing - } - - @Override - public void extend(HtmlRenderer.Builder rendererBuilder, String rendererType) { - rendererBuilder.nodeRendererFactory(new InsertAnchorNodeRenderer.Factory()); - } - - @Override - public void extend(Parser.Builder parserBuilder) { - if (ENABLE_INLINE_INSERT_ANCHORS.get(parserBuilder)) { - parserBuilder.customInlineParserExtensionFactory(new InsertAnchorInlineParser.Factory()); - } - } - - @Override - public void extend(Formatter.Builder builder) { - builder.nodeFormatterFactory(new InsertAnchorFormatter.Factory()); - } - - @Override - public void extend(FlexmarkHtmlConverter.Builder builder) { - builder.htmlNodeRendererFactory(new InsertAnchorHtmlNodeRenderer.Factory()); - } - - private static class InsertAnchorOptions { - public final boolean enableInlineInsertAnchors; - public final boolean enableRendering; - - public InsertAnchorOptions(DataHolder options) { - enableInlineInsertAnchors = ENABLE_INLINE_INSERT_ANCHORS.get(options); - enableRendering = ENABLE_RENDERING.get(options); - } - } - - private static class InsertAnchorNodeRenderer implements NodeRenderer { - private final InsertAnchorOptions options; - - public InsertAnchorNodeRenderer(DataHolder options) { - this.options = new InsertAnchorOptions(options); - } - - @Override - public Set> getNodeRenderingHandlers() { - return Collections.singleton(new NodeRenderingHandler<>(InsertAnchorNode.class, this::render)); - } - - @SuppressWarnings("unused") - protected void render(InsertAnchorNode node, NodeRendererContext context, HtmlWriter html) { - if (options.enableRendering) { - html.attr("type", node.getType()).attr("id-ref", node.getIdReference()).withAttr().tagVoid("insert"); - } - } - - // @Override - // public Set> getNodeRenderingHandlers() { - // HashSet> set = new - // HashSet>(); - // set.add(new NodeRenderingHandler(Macro.class, new - // CustomNodeRenderer() { - // @Override - // public void render(Macro node, NodeRendererContext context, HtmlWriter html) - // { - // MacroNodeRenderer.this.render(node, context, html); } - // })); - public static class Factory implements NodeRendererFactory { - - @Override - public NodeRenderer apply(DataHolder options) { - return new InsertAnchorNodeRenderer(options); - } - - } - - } - - private static class InsertAnchorInlineParser implements InlineParserExtension { - private static final Pattern PATTERN = Pattern.compile("\\{\\{\\s*insert:\\s*([^\\s]+),\\s*([^\\s]+)\\s*\\}\\}"); - - public InsertAnchorInlineParser(@SuppressWarnings("unused") LightInlineParser inlineParser) { - // do nothing - } - - @Override - public void finalizeDocument(InlineParser inlineParser) { - // do nothing - } - - @Override - public void finalizeBlock(InlineParser inlineParser) { - // do nothing - } - - @Override - public boolean parse(LightInlineParser inlineParser) { - if (inlineParser.peek() == '{') { - BasedSequence input = inlineParser.getInput(); - Matcher matcher = inlineParser.matcher(PATTERN); - if (matcher != null) { - BasedSequence type = input.subSequence(matcher.start(1), matcher.end(1)); - BasedSequence idReference = input.subSequence(matcher.start(2), matcher.end(2)); - assert type != null; - assert idReference != null; - inlineParser.appendNode(new InsertAnchorNode(type, idReference)); - return true; // NOPMD - readability - } - } - return false; - } - - public static class Factory implements InlineParserExtensionFactory { - @Override - public Set> getAfterDependents() { - return Collections.emptySet(); - } - - @Override - public CharSequence getCharacters() { - return "{"; - } - - @Override - public Set> getBeforeDependents() { - return Collections.emptySet(); - } - - @Override - public InlineParserExtension apply(LightInlineParser lightInlineParser) { - return new InsertAnchorInlineParser(lightInlineParser); - } - - @Override - public boolean affectsGlobalScope() { - return false; - } - } - } - - private static class InsertAnchorFormatter implements NodeFormatter { - private final InsertAnchorOptions options; - - public InsertAnchorFormatter(DataHolder options) { - this.options = new InsertAnchorOptions(options); - } - - @Override - public Set> getNodeFormattingHandlers() { - return options.enableInlineInsertAnchors - ? Collections.singleton(new NodeFormattingHandler<>(InsertAnchorNode.class, this::render)) - : Collections.emptySet(); - } - - @SuppressWarnings("unused") - protected void render(InsertAnchorNode node, NodeFormatterContext context, MarkdownWriter markdown) { - if (options.enableRendering) { - markdown.append("{{ insert: "); - markdown.append(node.getType()); - markdown.append(", "); - markdown.append(node.getIdReference()); - markdown.append(" }}"); - } - } - - @Override - public Set> getNodeClasses() { - return Collections.singleton(InsertAnchorNode.class); - } - - public static class Factory implements NodeFormatterFactory { - - @Override - public NodeFormatter create(DataHolder options) { - return new InsertAnchorFormatter(options); - } - - } - } - - private static class InsertAnchorHtmlNodeRenderer implements HtmlNodeRenderer { - private final InsertAnchorOptions options; - - public InsertAnchorHtmlNodeRenderer(DataHolder options) { - this.options = new InsertAnchorOptions(options); - } - - @Override - public Set> getHtmlNodeRendererHandlers() { - return options.enableInlineInsertAnchors - ? Collections.singleton(new HtmlNodeRendererHandler<>("insert", Element.class, this::processInsert)) - : Collections.emptySet(); - } - - private void processInsert( // NOPMD used as lambda - Element node, - @SuppressWarnings("unused") HtmlNodeConverterContext context, - HtmlMarkdownWriter out) { - - String type = node.attr("type"); - String idRef = node.attr("id-ref"); - - out.append("{{ insert: "); - out.append(type); - out.append(", "); - out.append(idRef); - out.append(" }}"); - } - - public static class Factory implements HtmlNodeRendererFactory { - - @Override - public HtmlNodeRenderer apply(DataHolder options) { - return new InsertAnchorHtmlNodeRenderer(options); - } - } - } - - public static class InsertAnchorNode - extends Node { - - @NonNull - private BasedSequence type; - @NonNull - private BasedSequence idReference; - - @SuppressWarnings("null") - public InsertAnchorNode(@NonNull String type, @NonNull String idReference) { - this(CharSubSequence.of(type), CharSubSequence.of(idReference)); - } - - public InsertAnchorNode(@NonNull BasedSequence type, @NonNull BasedSequence idReference) { - this.type = type; - this.idReference = idReference; - } - - @NonNull - public BasedSequence getType() { - return type; - } - - @NonNull - public BasedSequence getIdReference() { - return idReference; - } - - public void setIdReference(@NonNull BasedSequence value) { - this.idReference = value; - } - - @Override - @NonNull - public BasedSequence[] getSegments() { - @NonNull BasedSequence[] retval = { getType(), getIdReference() }; - return retval; - } - - @Override - public void getAstExtra(StringBuilder out) { - segmentSpanChars(out, getType(), "type"); - segmentSpanChars(out, getIdReference(), "id-ref"); - } - } -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.datatype.markup.flexmark; // NOPMD AST processor + +import com.vladsch.flexmark.formatter.Formatter; +import com.vladsch.flexmark.formatter.MarkdownWriter; +import com.vladsch.flexmark.formatter.NodeFormatter; +import com.vladsch.flexmark.formatter.NodeFormatterContext; +import com.vladsch.flexmark.formatter.NodeFormatterFactory; +import com.vladsch.flexmark.formatter.NodeFormattingHandler; +import com.vladsch.flexmark.html.HtmlRenderer; +import com.vladsch.flexmark.html.HtmlWriter; +import com.vladsch.flexmark.html.renderer.NodeRenderer; +import com.vladsch.flexmark.html.renderer.NodeRendererContext; +import com.vladsch.flexmark.html.renderer.NodeRendererFactory; +import com.vladsch.flexmark.html.renderer.NodeRenderingHandler; +import com.vladsch.flexmark.html2md.converter.FlexmarkHtmlConverter; +import com.vladsch.flexmark.html2md.converter.HtmlMarkdownWriter; +import com.vladsch.flexmark.html2md.converter.HtmlNodeConverterContext; +import com.vladsch.flexmark.html2md.converter.HtmlNodeRenderer; +import com.vladsch.flexmark.html2md.converter.HtmlNodeRendererFactory; +import com.vladsch.flexmark.html2md.converter.HtmlNodeRendererHandler; +import com.vladsch.flexmark.parser.InlineParser; +import com.vladsch.flexmark.parser.InlineParserExtension; +import com.vladsch.flexmark.parser.InlineParserExtensionFactory; +import com.vladsch.flexmark.parser.LightInlineParser; +import com.vladsch.flexmark.parser.Parser; +import com.vladsch.flexmark.util.ast.Node; +import com.vladsch.flexmark.util.data.DataHolder; +import com.vladsch.flexmark.util.data.DataKey; +import com.vladsch.flexmark.util.data.MutableDataHolder; +import com.vladsch.flexmark.util.misc.Extension; +import com.vladsch.flexmark.util.sequence.BasedSequence; +import com.vladsch.flexmark.util.sequence.CharSubSequence; + +import org.jsoup.nodes.Element; + +import java.util.Collections; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class InsertAnchorExtension + implements Parser.ParserExtension, HtmlRenderer.HtmlRendererExtension, + Formatter.FormatterExtension, FlexmarkHtmlConverter.HtmlConverterExtension { + public 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); + + public static Extension create() { + return new InsertAnchorExtension(); + } + + @Override + public void parserOptions(MutableDataHolder options) { + // do nothing + } + + @Override + public void rendererOptions(MutableDataHolder options) { + // do nothing + } + + @Override + public void extend(HtmlRenderer.Builder rendererBuilder, String rendererType) { + rendererBuilder.nodeRendererFactory(new InsertAnchorNodeRenderer.Factory()); + } + + @Override + public void extend(Parser.Builder parserBuilder) { + if (ENABLE_INLINE_INSERT_ANCHORS.get(parserBuilder)) { + parserBuilder.customInlineParserExtensionFactory(new InsertAnchorInlineParser.Factory()); + } + } + + @Override + public void extend(Formatter.Builder builder) { + builder.nodeFormatterFactory(new InsertAnchorFormatter.Factory()); + } + + @Override + public void extend(FlexmarkHtmlConverter.Builder builder) { + builder.htmlNodeRendererFactory(new InsertAnchorHtmlNodeRenderer.Factory()); + } + + private static class InsertAnchorOptions { + public final boolean enableInlineInsertAnchors; + public final boolean enableRendering; + + public InsertAnchorOptions(DataHolder options) { + enableInlineInsertAnchors = ENABLE_INLINE_INSERT_ANCHORS.get(options); + enableRendering = ENABLE_RENDERING.get(options); + } + } + + private static class InsertAnchorNodeRenderer implements NodeRenderer { + private final InsertAnchorOptions options; + + public InsertAnchorNodeRenderer(DataHolder options) { + this.options = new InsertAnchorOptions(options); + } + + @Override + public Set> getNodeRenderingHandlers() { + return Collections.singleton(new NodeRenderingHandler<>(InsertAnchorNode.class, this::render)); + } + + @SuppressWarnings("unused") + protected void render(InsertAnchorNode node, NodeRendererContext context, HtmlWriter html) { + if (options.enableRendering) { + html.attr("type", node.getType()).attr("id-ref", node.getIdReference()).withAttr().tagVoid("insert"); + } + } + + // @Override + // public Set> getNodeRenderingHandlers() { + // HashSet> set = new + // HashSet>(); + // set.add(new NodeRenderingHandler(Macro.class, new + // CustomNodeRenderer() { + // @Override + // public void render(Macro node, NodeRendererContext context, HtmlWriter html) + // { + // MacroNodeRenderer.this.render(node, context, html); } + // })); + public static class Factory implements NodeRendererFactory { + + @Override + public NodeRenderer apply(DataHolder options) { + return new InsertAnchorNodeRenderer(options); + } + + } + + } + + private static class InsertAnchorInlineParser implements InlineParserExtension { + private static final Pattern PATTERN = Pattern.compile("\\{\\{\\s*insert:\\s*([^\\s]+),\\s*([^\\s]+)\\s*\\}\\}"); + + public InsertAnchorInlineParser(@SuppressWarnings("unused") LightInlineParser inlineParser) { + // do nothing + } + + @Override + public void finalizeDocument(InlineParser inlineParser) { + // do nothing + } + + @Override + public void finalizeBlock(InlineParser inlineParser) { + // do nothing + } + + @Override + public boolean parse(LightInlineParser inlineParser) { + if (inlineParser.peek() == '{') { + BasedSequence input = inlineParser.getInput(); + Matcher matcher = inlineParser.matcher(PATTERN); + if (matcher != null) { + BasedSequence type = input.subSequence(matcher.start(1), matcher.end(1)); + BasedSequence idReference = input.subSequence(matcher.start(2), matcher.end(2)); + assert type != null; + assert idReference != null; + inlineParser.appendNode(new InsertAnchorNode(type, idReference)); + return true; // NOPMD - readability + } + } + return false; + } + + public static class Factory implements InlineParserExtensionFactory { + @Override + public Set> getAfterDependents() { + return Collections.emptySet(); + } + + @Override + public CharSequence getCharacters() { + return "{"; + } + + @Override + public Set> getBeforeDependents() { + return Collections.emptySet(); + } + + @Override + public InlineParserExtension apply(LightInlineParser lightInlineParser) { + return new InsertAnchorInlineParser(lightInlineParser); + } + + @Override + public boolean affectsGlobalScope() { + return false; + } + } + } + + private static class InsertAnchorFormatter implements NodeFormatter { + private final InsertAnchorOptions options; + + public InsertAnchorFormatter(DataHolder options) { + this.options = new InsertAnchorOptions(options); + } + + @Override + public Set> getNodeFormattingHandlers() { + return options.enableInlineInsertAnchors + ? Collections.singleton(new NodeFormattingHandler<>(InsertAnchorNode.class, this::render)) + : Collections.emptySet(); + } + + @SuppressWarnings("unused") + protected void render(InsertAnchorNode node, NodeFormatterContext context, MarkdownWriter markdown) { + if (options.enableRendering) { + markdown.append("{{ insert: "); + markdown.append(node.getType()); + markdown.append(", "); + markdown.append(node.getIdReference()); + markdown.append(" }}"); + } + } + + @Override + public Set> getNodeClasses() { + return Collections.singleton(InsertAnchorNode.class); + } + + public static class Factory implements NodeFormatterFactory { + + @Override + public NodeFormatter create(DataHolder options) { + return new InsertAnchorFormatter(options); + } + + } + } + + private static class InsertAnchorHtmlNodeRenderer implements HtmlNodeRenderer { + private final InsertAnchorOptions options; + + public InsertAnchorHtmlNodeRenderer(DataHolder options) { + this.options = new InsertAnchorOptions(options); + } + + @Override + public Set> getHtmlNodeRendererHandlers() { + return options.enableInlineInsertAnchors + ? Collections.singleton(new HtmlNodeRendererHandler<>("insert", Element.class, this::processInsert)) + : Collections.emptySet(); + } + + private void processInsert( // NOPMD used as lambda + Element node, + @SuppressWarnings("unused") HtmlNodeConverterContext context, + HtmlMarkdownWriter out) { + + String type = node.attr("type"); + String idRef = node.attr("id-ref"); + + out.append("{{ insert: "); + out.append(type); + out.append(", "); + out.append(idRef); + out.append(" }}"); + } + + public static class Factory implements HtmlNodeRendererFactory { + + @Override + public HtmlNodeRenderer apply(DataHolder options) { + return new InsertAnchorHtmlNodeRenderer(options); + } + } + } + + public static class InsertAnchorNode + extends Node { + + @NonNull + private BasedSequence type; + @NonNull + private BasedSequence idReference; + + @SuppressWarnings("null") + public InsertAnchorNode(@NonNull String type, @NonNull String idReference) { + this(CharSubSequence.of(type), CharSubSequence.of(idReference)); + } + + public InsertAnchorNode(@NonNull BasedSequence type, @NonNull BasedSequence idReference) { + this.type = type; + this.idReference = idReference; + } + + @NonNull + public BasedSequence getType() { + return type; + } + + @NonNull + public BasedSequence getIdReference() { + return idReference; + } + + public void setIdReference(@NonNull BasedSequence value) { + this.idReference = value; + } + + @Override + @NonNull + public BasedSequence[] getSegments() { + @NonNull BasedSequence[] retval = { getType(), getIdReference() }; + return retval; + } + + @Override + public void getAstExtra(StringBuilder out) { + segmentSpanChars(out, getType(), "type"); + segmentSpanChars(out, getIdReference(), "id-ref"); + } + } +} 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/MarkupXmlEventWriter.java index 16806f8e2..9c5dbd9d7 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/MarkupXmlEventWriter.java @@ -28,6 +28,7 @@ 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; 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/MarkupXmlStreamWriter.java index 3f79e7f4f..6c9d526cc 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/MarkupXmlStreamWriter.java @@ -28,6 +28,8 @@ 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; 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/flexmark/XmlMarkupParser.java index cfe2b8959..1ba89bdc9 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/flexmark/XmlMarkupParser.java @@ -1,247 +1,247 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -package gov.nist.secauto.metaschema.core.datatype.markup.flexmark; - -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; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.codehaus.stax2.XMLEventReader2; - -import java.util.Set; - -import javax.xml.namespace.QName; -import javax.xml.stream.XMLStreamConstants; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.events.Attribute; -import javax.xml.stream.events.Characters; -import javax.xml.stream.events.StartElement; -import javax.xml.stream.events.XMLEvent; - -import edu.umd.cs.findbugs.annotations.NonNull; - -public final class XmlMarkupParser { - private static final Logger LOGGER = LogManager.getLogger(XmlMarkupParser.class); - - @NonNull - public static final Set BLOCK_ELEMENTS = ObjectUtils.notNull( - Set.of( - "h1", - "h2", - "h3", - "h4", - "h5", - "h6", - "ul", - "ol", - "pre", - "hr", - "blockquote", - "p", - "table", - "img")); - - @NonNull - private static final XmlMarkupParser SINGLETON = new XmlMarkupParser(); - - @SuppressWarnings("PMD.AvoidSynchronizedAtMethodLevel") - @NonNull - public static synchronized XmlMarkupParser instance() { - return SINGLETON; - } - - private XmlMarkupParser() { - // disable construction - } - - public MarkupLine parseMarkupline(XMLEventReader2 reader) throws XMLStreamException { // NOPMD - acceptable - StringBuilder buffer = new StringBuilder(); - parseContents(reader, null, buffer); - String html = buffer.toString().trim(); - return html.isEmpty() ? null : MarkupLine.fromHtml(html); - } - - public MarkupMultiline parseMarkupMultiline(XMLEventReader2 reader) throws XMLStreamException { - StringBuilder buffer = new StringBuilder(); - parseToString(reader, buffer); - String html = buffer.toString().trim(); - - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("XML->HTML: {}", html); - } - return html.isEmpty() ? null : MarkupMultiline.fromHtml(html); - } - - private void parseToString(XMLEventReader2 reader, StringBuilder buffer) // NOPMD - acceptable - throws XMLStreamException { - // if (LOGGER.isDebugEnabled()) { - // LOGGER.debug("parseToString(enter): {}", - // XmlEventUtil.toString(reader.peek())); - // } - - outer: while (reader.hasNextEvent() && !reader.peek().isEndElement()) { - // skip whitespace before the next block element - XMLEvent nextEvent = XmlEventUtil.skipWhitespace(reader); - - // if (LOGGER.isDebugEnabled()) { - // LOGGER.debug("parseToString: {}", XmlEventUtil.toString(nextEvent)); - // } - - if (nextEvent.isStartElement()) { - StartElement start = nextEvent.asStartElement(); - QName name = start.getName(); - - // Note: the next element is not consumed. The called method is expected to - // consume it - if (BLOCK_ELEMENTS.contains(name.getLocalPart())) { - parseStartElement(reader, start, buffer); - - // the next event should be the event after the start's END_ELEMENT - // assert XmlEventUtil.isNextEventEndElement(reader, name) : - // XmlEventUtil.toString(reader.peek()); - } else { - // throw new IllegalStateException(); - // stop parsing on first unrecognized event - break outer; - } - } - // reader.nextEvent(); - - // skip whitespace before the next block element - XmlEventUtil.skipWhitespace(reader); - } - - // if (LOGGER.isDebugEnabled()) { - // LOGGER.debug("parseToString(exit): {}", reader.peek() != null ? - // XmlEventUtil.toString(reader.peek()) : ""); - // } - } - - private void parseStartElement(XMLEventReader2 reader, StartElement start, StringBuilder buffer) - throws XMLStreamException { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("parseStartElement(enter): {}", XmlEventUtil.toString(start)); - } - - // consume the start event - reader.nextEvent(); - - QName name = start.getName(); - buffer.append('<') - .append(name.getLocalPart()); - for (Attribute attribute : CollectionUtil.toIterable( - ObjectUtils.notNull(start.getAttributes()))) { - buffer - .append(' ') - .append(attribute.getName().getLocalPart()) - .append("=\"") - .append(attribute.getValue()) - .append('"'); - } - - XMLEvent next = reader.peek(); - if (next != null && next.isEndElement()) { - buffer.append("/>"); - // consume end element event - reader.nextEvent(); - } else { - buffer.append('>'); - - // parse until the start's END_ELEMENT is reached - parseContents(reader, start, buffer); - - buffer - .append("'); - - // the next event should be the start's END_ELEMENT - XmlEventUtil.assertNext(reader, XMLStreamConstants.END_ELEMENT, name); - - // consume the start's END_ELEMENT - reader.nextEvent(); - } - - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("parseStartElement(exit): {}", reader.peek() != null ? XmlEventUtil.toString(reader.peek()) : ""); - } - } - - private void parseContents(XMLEventReader2 reader, StartElement start, StringBuilder buffer) - throws XMLStreamException { - // if (LOGGER.isDebugEnabled()) { - // LOGGER.debug("parseContents(enter): {}", - // XmlEventUtil.toString(reader.peek())); - // } - - XMLEvent event; - while (reader.hasNextEvent() && !(event = reader.peek()).isEndElement()) { - // // skip whitespace before the next list item - // event = XmlEventUtil.skipWhitespace(reader); - - // if (LOGGER.isDebugEnabled()) { - // LOGGER.debug("parseContents(before): {}", XmlEventUtil.toString(event)); - // } - - if (event.isStartElement()) { - StartElement nextStart = event.asStartElement(); - // QName nextName = nextStart.getName(); - parseStartElement(reader, nextStart, buffer); - - // if (LOGGER.isDebugEnabled()) { - // LOGGER.debug("parseContents(after): {}", - // XmlEventUtil.toString(reader.peek())); - // } - - // assert XmlEventUtil.isNextEventEndElement(reader, nextName) : - // XmlEventUtil.toString(reader.peek()); - - // reader.nextEvent(); - } else if (event.isCharacters()) { - Characters characters = event.asCharacters(); - buffer.append(Escaping.escapeHtml(characters.getData(), true)); - reader.nextEvent(); - } - } - - assert start == null - || XmlEventUtil.isEventEndElement(reader.peek(), ObjectUtils.notNull(start.getName())) : XmlEventUtil - .generateExpectedMessage(reader.peek(), XMLStreamConstants.END_ELEMENT, start.getName()); - - // if (LOGGER.isDebugEnabled()) { - // LOGGER.debug("parseContents(exit): {}", reader.peek() != null ? - // XmlEventUtil.toString(reader.peek()) : ""); - // } - } - -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.datatype.markup.flexmark; + +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; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.codehaus.stax2.XMLEventReader2; + +import java.util.Set; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Attribute; +import javax.xml.stream.events.Characters; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public final class XmlMarkupParser { + private static final Logger LOGGER = LogManager.getLogger(XmlMarkupParser.class); + + @NonNull + public static final Set BLOCK_ELEMENTS = ObjectUtils.notNull( + Set.of( + "h1", + "h2", + "h3", + "h4", + "h5", + "h6", + "ul", + "ol", + "pre", + "hr", + "blockquote", + "p", + "table", + "img")); + + @NonNull + private static final XmlMarkupParser SINGLETON = new XmlMarkupParser(); + + @SuppressWarnings("PMD.AvoidSynchronizedAtMethodLevel") + @NonNull + public static synchronized XmlMarkupParser instance() { + return SINGLETON; + } + + private XmlMarkupParser() { + // disable construction + } + + public MarkupLine parseMarkupline(XMLEventReader2 reader) throws XMLStreamException { // NOPMD - acceptable + StringBuilder buffer = new StringBuilder(); + parseContents(reader, null, buffer); + String html = buffer.toString().trim(); + return html.isEmpty() ? null : MarkupLine.fromHtml(html); + } + + public MarkupMultiline parseMarkupMultiline(XMLEventReader2 reader) throws XMLStreamException { + StringBuilder buffer = new StringBuilder(); + parseToString(reader, buffer); + String html = buffer.toString().trim(); + + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("XML->HTML: {}", html); + } + return html.isEmpty() ? null : MarkupMultiline.fromHtml(html); + } + + private void parseToString(XMLEventReader2 reader, StringBuilder buffer) // NOPMD - acceptable + throws XMLStreamException { + // if (LOGGER.isDebugEnabled()) { + // LOGGER.debug("parseToString(enter): {}", + // XmlEventUtil.toString(reader.peek())); + // } + + outer: while (reader.hasNextEvent() && !reader.peek().isEndElement()) { + // skip whitespace before the next block element + XMLEvent nextEvent = XmlEventUtil.skipWhitespace(reader); + + // if (LOGGER.isDebugEnabled()) { + // LOGGER.debug("parseToString: {}", XmlEventUtil.toString(nextEvent)); + // } + + if (nextEvent.isStartElement()) { + StartElement start = nextEvent.asStartElement(); + QName name = start.getName(); + + // Note: the next element is not consumed. The called method is expected to + // consume it + if (BLOCK_ELEMENTS.contains(name.getLocalPart())) { + parseStartElement(reader, start, buffer); + + // the next event should be the event after the start's END_ELEMENT + // assert XmlEventUtil.isNextEventEndElement(reader, name) : + // XmlEventUtil.toString(reader.peek()); + } else { + // throw new IllegalStateException(); + // stop parsing on first unrecognized event + break outer; + } + } + // reader.nextEvent(); + + // skip whitespace before the next block element + XmlEventUtil.skipWhitespace(reader); + } + + // if (LOGGER.isDebugEnabled()) { + // LOGGER.debug("parseToString(exit): {}", reader.peek() != null ? + // XmlEventUtil.toString(reader.peek()) : ""); + // } + } + + private void parseStartElement(XMLEventReader2 reader, StartElement start, StringBuilder buffer) + throws XMLStreamException { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("parseStartElement(enter): {}", XmlEventUtil.toString(start)); + } + + // consume the start event + reader.nextEvent(); + + QName name = start.getName(); + buffer.append('<') + .append(name.getLocalPart()); + for (Attribute attribute : CollectionUtil.toIterable( + ObjectUtils.notNull(start.getAttributes()))) { + buffer + .append(' ') + .append(attribute.getName().getLocalPart()) + .append("=\"") + .append(attribute.getValue()) + .append('"'); + } + + XMLEvent next = reader.peek(); + if (next != null && next.isEndElement()) { + buffer.append("/>"); + // consume end element event + reader.nextEvent(); + } else { + buffer.append('>'); + + // parse until the start's END_ELEMENT is reached + parseContents(reader, start, buffer); + + buffer + .append("'); + + // the next event should be the start's END_ELEMENT + XmlEventUtil.assertNext(reader, XMLStreamConstants.END_ELEMENT, name); + + // consume the start's END_ELEMENT + reader.nextEvent(); + } + + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("parseStartElement(exit): {}", reader.peek() != null ? XmlEventUtil.toString(reader.peek()) : ""); + } + } + + private void parseContents(XMLEventReader2 reader, StartElement start, StringBuilder buffer) + throws XMLStreamException { + // if (LOGGER.isDebugEnabled()) { + // LOGGER.debug("parseContents(enter): {}", + // XmlEventUtil.toString(reader.peek())); + // } + + XMLEvent event; + while (reader.hasNextEvent() && !(event = reader.peek()).isEndElement()) { + // // skip whitespace before the next list item + // event = XmlEventUtil.skipWhitespace(reader); + + // if (LOGGER.isDebugEnabled()) { + // LOGGER.debug("parseContents(before): {}", XmlEventUtil.toString(event)); + // } + + if (event.isStartElement()) { + StartElement nextStart = event.asStartElement(); + // QName nextName = nextStart.getName(); + parseStartElement(reader, nextStart, buffer); + + // if (LOGGER.isDebugEnabled()) { + // LOGGER.debug("parseContents(after): {}", + // XmlEventUtil.toString(reader.peek())); + // } + + // assert XmlEventUtil.isNextEventEndElement(reader, nextName) : + // XmlEventUtil.toString(reader.peek()); + + // reader.nextEvent(); + } else if (event.isCharacters()) { + Characters characters = event.asCharacters(); + buffer.append(Escaping.escapeHtml(characters.getData(), true)); + reader.nextEvent(); + } + } + + assert start == null + || XmlEventUtil.isEventEndElement(reader.peek(), ObjectUtils.notNull(start.getName())) : XmlEventUtil + .generateExpectedMessage(reader.peek(), XMLStreamConstants.END_ELEMENT, start.getName()); + + // if (LOGGER.isDebugEnabled()) { + // LOGGER.debug("parseContents(exit): {}", reader.peek() != null ? + // XmlEventUtil.toString(reader.peek()) : ""); + // } + } + +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/AbstractMarkupWriter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/AbstractMarkupWriter.java similarity index 98% rename from core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/AbstractMarkupWriter.java rename to core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/AbstractMarkupWriter.java index 056edf3ca..97ce2f32b 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/AbstractMarkupWriter.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/AbstractMarkupWriter.java @@ -24,7 +24,7 @@ * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. */ -package gov.nist.secauto.metaschema.core.datatype.markup.flexmark; // NOPMD AST processor has many members +package gov.nist.secauto.metaschema.core.datatype.markup.flexmark.impl; // NOPMD AST processor has many members import com.vladsch.flexmark.ast.AutoLink; import com.vladsch.flexmark.ast.BlockQuote; @@ -64,6 +64,7 @@ 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; @@ -111,9 +112,11 @@ public abstract class AbstractMarkupWriter // NOPMD not // normal cases // ENTITY_MAP.put("&", "&"); /* - * ENTITY_MAP.put("‘", "‘"); ENTITY_MAP.put("’", "’"); ENTITY_MAP.put("…", "…"); - * ENTITY_MAP.put("—", "—"); ENTITY_MAP.put("–", "–"); ENTITY_MAP.put("“", "“"); - * ENTITY_MAP.put("”", "”"); ENTITY_MAP.put("«", "«"); ENTITY_MAP.put("»", "»"); + * ENTITY_MAP.put("‘", "‘"); ENTITY_MAP.put("’", "’"); + * ENTITY_MAP.put("…", "…"); ENTITY_MAP.put("—", "—"); + * ENTITY_MAP.put("–", "–"); ENTITY_MAP.put("“", "“"); + * ENTITY_MAP.put("”", "”"); ENTITY_MAP.put("«", "«"); + * ENTITY_MAP.put("»", "»"); */ } 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 index 7728a397b..290b67be4 100644 --- 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 @@ -1,54 +1,54 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -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()); - } -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +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 index e3bd4593e..5c48fc262 100644 --- 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 @@ -1,54 +1,54 @@ -/* - * Portions of this software was developed by employees of the National Institute - * of Standards and Technology (NIST), an agency of the Federal Government and is - * being made available as a public service. Pursuant to title 17 United States - * Code Section 105, works of NIST employees are not subject to copyright - * protection in the United States. This software may be subject to foreign - * copyright. Permission in the United States and in foreign countries, to the - * extent that NIST may hold copyright, to use, copy, modify, create derivative - * works, and distribute this software and its documentation without fee is hereby - * granted on a non-exclusive basis, provided that this notice and disclaimer - * of warranty appears in all copies. - * - * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER - * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY - * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM - * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE - * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT - * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, - * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, - * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, - * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR - * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT - * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. - */ - -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()); - } -} +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +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/AbstractCodedMetapathException.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/AbstractCodedMetapathException.java index 64b1b3399..5b822836e 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/AbstractCodedMetapathException.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/AbstractCodedMetapathException.java @@ -97,7 +97,7 @@ public String getMessage() { * * @return the error code value */ - protected int getCode() { + public int getCode() { return code; } @@ -106,7 +106,7 @@ protected int getCode() { * * @return the error code family */ - protected abstract String getCodePrefix(); + public abstract String getCodePrefix(); /** * Get a combination of the error code family and value. diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/DynamicContext.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/DynamicContext.java index 0b13b5479..a9f17e2db 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/DynamicContext.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/DynamicContext.java @@ -45,6 +45,8 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import javax.xml.namespace.QName; + import edu.umd.cs.findbugs.annotations.NonNull; // TODO: add support for in-scope namespaces @@ -54,17 +56,21 @@ */ public class DynamicContext { // NOPMD - intentional data class @NonNull - private final Map> letVariableMap; + private final Map> letVariableMap; @NonNull private final SharedState sharedState; + public DynamicContext() { + this(StaticContext.instance()); + } + /** * Construct a new Metapath dynamic context. * * @param staticContext * the Metapath static context */ - DynamicContext(@NonNull StaticContext staticContext) { + public DynamicContext(@NonNull StaticContext staticContext) { this.letVariableMap = new ConcurrentHashMap<>(); this.sharedState = new SharedState(staticContext); } @@ -181,8 +187,15 @@ public void cacheResult(@NonNull CallingContext callingContext, @NonNull ISequen } @NonNull - public ISequence getVariableValue(@NonNull String name) { - return ObjectUtils.requireNonNull(letVariableMap.get(name)); + public ISequence getVariableValue(@NonNull QName name) { + ISequence retval = letVariableMap.get(name); + if (retval == null) { + if (!letVariableMap.containsKey(name)) { + throw new MetapathException(String.format("Variable '%s' not defined in context.", name)); + } + throw new MetapathException(String.format("Variable '%s' has null contents.", name)); + } + return retval; } /** @@ -193,7 +206,7 @@ public ISequence getVariableValue(@NonNull String name) { * @param boundValue * the value to bind to the variable */ - public void bindVariableValue(@NonNull String name, @NonNull ISequence boundValue) { + public void bindVariableValue(@NonNull QName name, @NonNull ISequence boundValue) { letVariableMap.put(name, boundValue); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/DynamicMetapathException.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/DynamicMetapathException.java index df5f8fcc0..2b432fad5 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/DynamicMetapathException.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/DynamicMetapathException.java @@ -105,7 +105,7 @@ public DynamicMetapathException(int code, Throwable cause) { } @Override - protected String getCodePrefix() { + public String getCodePrefix() { return "MPDY"; } } 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 new file mode 100644 index 000000000..1e83efe8d --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/EQNameUtils.java @@ -0,0 +1,101 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; + +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; + +public final class EQNameUtils { + private static final Pattern URI_QUALIFIED_NAME = Pattern.compile("^Q\\{([^{}]*)\\}(.+)$"); + private static final Pattern LEXICAL_NAME = Pattern.compile("^(?:([^:]+):)?(.+)$"); + private static final Pattern NCNAME = Pattern.compile(String.format("^(\\p{L}|_)(\\p{L}|\\p{N}|[.\\-_])*$")); + + private EQNameUtils() { + // disable construction + } + + @NonNull + public static QName parseName( + @NonNull String name, + @Nullable IEQNamePrefixResolver resolver) { + Matcher matcher = URI_QUALIFIED_NAME.matcher(name); + return matcher.matches() + ? newUriQualifiedName(matcher) + : parseLexicalQName(name, resolver); + } + + @NonNull + public static QName parseUriQualifiedName(@NonNull String name) { + Matcher matcher = URI_QUALIFIED_NAME.matcher(name); + if (!matcher.matches()) { + throw new IllegalArgumentException( + String.format("The name '%s' is not a valid BracedURILiteral of the form: Q{URI}local-name", name)); + } + return newUriQualifiedName(matcher); + } + + @NonNull + private static QName newUriQualifiedName(@NonNull Matcher matcher) { + return new QName(matcher.group(1), matcher.group(2)); + } + + @NonNull + public static QName parseLexicalQName( + @NonNull String name, + @Nullable IEQNamePrefixResolver resolver) { + Matcher matcher = LEXICAL_NAME.matcher(name); + if (!matcher.matches()) { + throw new IllegalArgumentException( + String.format("The name '%s' is not a valid lexical QName of the form: prefix:local-name or local-name", + name)); + } + String prefix = matcher.group(1); + + if (prefix == null) { + prefix = XMLConstants.DEFAULT_NS_PREFIX; + } + + String namespace = resolver == null ? XMLConstants.NULL_NS_URI : resolver.resolve(prefix); + return new QName(namespace, matcher.group(2), prefix); + } + + public static boolean isNcName(@NonNull String name) { + return NCNAME.matcher(name).matches(); + } + + @FunctionalInterface + public interface IEQNamePrefixResolver { + @NonNull + String resolve(@NonNull String prefix); + } +} 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 new file mode 100644 index 000000000..58520adcc --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/ICollectionValue.java @@ -0,0 +1,50 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath; + +import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.stream.Stream; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public interface ICollectionValue { + // TODO: rename to toSequence and resolve conflicting methods? + @NonNull + ISequence asSequence(); + + @NonNull + static Stream normalizeAsItems(@NonNull ICollectionValue value) { + return value instanceof IItem + ? ObjectUtils.notNull(Stream.of((IItem) value)) + : value.asSequence().stream(); + } + + @NonNull + Stream flatten(); +} diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/IBindingDefinitionFlag.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/IPrintable.java similarity index 87% rename from databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/IBindingDefinitionFlag.java rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/IPrintable.java index ee6f5e956..0cae7cbcc 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/IBindingDefinitionFlag.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/IPrintable.java @@ -24,10 +24,16 @@ * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. */ -package gov.nist.secauto.metaschema.databind.model.metaschema; +package gov.nist.secauto.metaschema.core.metapath; -import gov.nist.secauto.metaschema.core.model.IFlagDefinition; +import edu.umd.cs.findbugs.annotations.NonNull; -public interface IBindingDefinitionFlag extends IFlagDefinition, IBindingDefinition { - // no additional methods +public interface IPrintable { + /** + * Get the string value. + * + * @return the string value + */ + @NonNull + String asString(); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/ISequence.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/ISequence.java index 569f3ccac..0fe805b7b 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/ISequence.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/ISequence.java @@ -26,20 +26,22 @@ package gov.nist.secauto.metaschema.core.metapath; +import gov.nist.secauto.metaschema.core.metapath.impl.AbstractSequence; +import gov.nist.secauto.metaschema.core.metapath.impl.SequenceN; +import gov.nist.secauto.metaschema.core.metapath.impl.SingletonSequence; +import gov.nist.secauto.metaschema.core.metapath.impl.StreamSequence; import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.IArrayItem; import gov.nist.secauto.metaschema.core.util.ObjectUtils; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; -import java.util.ListIterator; import java.util.Set; import java.util.function.BiConsumer; import java.util.function.BinaryOperator; -import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collector; @@ -54,125 +56,118 @@ * Items is a sequence are typically ordered based on their position in the * original node graph based on a depth first ordering. * - * @param + * @param * the Java type of the items in a sequence */ -public interface ISequence extends List { - @SuppressWarnings("rawtypes") - ISequence EMPTY = new EmptyListImpl<>(); - +@SuppressWarnings("PMD.ShortMethodName") +public interface ISequence extends List, IPrintable, ICollectionValue { /** * Get an empty sequence. * - * @param + * @param * the item type * @return the empty sequence */ - @SuppressWarnings({ "unchecked", "null" }) + @SuppressWarnings("null") @NonNull - static ISequence empty() { - return EMPTY; + static ISequence empty() { + return AbstractSequence.empty(); + } + + @Override + default Iterator iterator() { + return getValue().listIterator(); } /** - * Construct a new sequence containing the provided {@code item}. - *

- * If the item is {@code null} and empty sequence will be created. + * Get the items in this sequence as a {@link List}. * - * @param - * the type of items contained in the sequence. - * @param item - * the item to add to the sequence - * @return the new sequence + * @return a list containing all the items of the sequence */ @NonNull - static ISequence of( // NOPMD - intentional - @Nullable ITEM_TYPE item) { - ISequence retval; - if (item == null) { - retval = empty(); - } else { - retval = new SingletonSequenceImpl<>(item); - } - return retval; - } + List getValue(); /** - * Construct a new sequence containing the provided {@code items}. + * Get the items in this sequence as a {@link Stream}. * - * @param - * the type of items contained in the sequence. - * @param items - * the items to add to the sequence - * @return the new sequence + * @return a stream containing all the items of the sequence */ - @SafeVarargs + @Override @NonNull - static ISequence of( // NOPMD - intentional - @NonNull ITEM_TYPE... items) { - return of(ObjectUtils.notNull(Arrays.asList(items))); - } + Stream stream(); /** - * Construct a new sequence containing the provided {@code items}. + * Retrieves the first item in a sequence. If the sequence is empty, a + * {@code null} result is returned. If requireSingleton is {@code true} and the + * sequence contains more than one item, a {@link TypeMetapathException} is + * thrown. * - * @param - * the type of items contained in the sequence. + * @param + * the item type to return derived from the provided sequence * @param items - * the items to add to the sequence - * @return the new sequence + * the sequence to retrieve the first item from + * @param requireSingleton + * if {@code true} then a {@link TypeMetapathException} is thrown if + * the sequence contains more than one item + * @return {@code null} if the sequence is empty, or the item otherwise + * @throws TypeMetapathException + * if the sequence contains more than one item and requireSingleton is + * {@code true} */ - @NonNull - static ISequence of( // NOPMD - intentional - @NonNull List items) { - ISequence retval; - if (items.isEmpty()) { - retval = empty(); - } else if (items.size() == 1) { - retval = new SingletonSequenceImpl<>(ObjectUtils.notNull(items.iterator().next())); - } else { - retval = new ListSequenceImpl<>(items); - } - return retval; + static T getFirstItem(@NonNull ISequence items, boolean requireSingleton) { + return getFirstItem(items.stream(), requireSingleton); } /** - * Construct a new sequence containing the provided {@code items}. + * Retrieves the first item in a sequence. If the sequence is empty, a + * {@code null} result is returned. If requireSingleton is {@code true} and the + * sequence contains more than one item, a {@link TypeMetapathException} is + * thrown. * - * @param - * the type of items contained in the sequence. + * @param + * the item type to return derived from the provided sequence * @param items - * the items to add to the sequence - * @return the new sequence + * the sequence to retrieve the first item from + * @param requireSingleton + * if {@code true} then a {@link TypeMetapathException} is thrown if + * the sequence contains more than one item + * @return {@code null} if the sequence is empty, or the item otherwise + * @throws TypeMetapathException + * if the sequence contains more than one item and requireSingleton is + * {@code true} */ - // TODO: remove null check on callers - @NonNull - static ISequence of( // NOPMD - intentional - Stream items) { - return items == null ? empty() : new StreamSequenceImpl<>(items); + static T getFirstItem(@NonNull Stream items, boolean requireSingleton) { + return items.limit(2) + .reduce((t, u) -> { + if (requireSingleton) { + throw new InvalidTypeMetapathException( + null, + String.format("sequence expected to contain only one item, but found multiple")); + } + return t; + }).orElse(null); } - @Override - default Iterator iterator() { - return asList().listIterator(); + @Nullable + default ITEM getFirstItem(boolean requireSingleton) { + return getFirstItem(this, requireSingleton); } - /** - * Get the items in this sequence as a {@link List}. - * - * @return a list containing all the items of the sequence - */ - @NonNull - List asList(); - - /** - * Get the items in this sequence as a {@link Stream}. - * - * @return a stream containing all the items of the sequence - */ - // TODO: rename to "stream" @NonNull - Stream asStream(); + default ICollectionValue toCollectionValue() { + ICollectionValue retval; + switch (size()) { + case 0: + retval = empty(); + break; + case 1: + retval = ObjectUtils.notNull(stream().findFirst().get()); + break; + default: + retval = this; + } + return retval; + } /** * Get a stream guaranteed to be backed by a list. @@ -180,46 +175,16 @@ default Iterator iterator() { * @return the stream */ @NonNull - default Stream safeStream() { - return ObjectUtils.notNull(asList().stream()); + default Stream safeStream() { + return ObjectUtils.notNull(getValue().stream()); } - /** - * This optional operation ensures that a list is used to back this sequence. - *

- * If a stream is currently backing this sequence, the stream will be collected - * into a list. This ensures the sequence can be visited multiple times. - * - * @return the resulting sequence - */ - @NonNull - ISequence collect(); - - /** - * Determine if this sequence is empty. - * - * @return {@code true} if the sequence contains no items, or {@code false} - * otherwise - */ - @Override - boolean isEmpty(); - - /** - * Get the count of items in this sequence. - * - * @return the count of items - */ - @Override - int size(); - - /** - * Iterate over each item in the sequence using the provided {@code action}. - * - * @param action - * code to execute for each item - */ + @SuppressWarnings("null") @Override - void forEach(Consumer action); + default Stream flatten() { + // TODO: Is a safe stream needed here? + return safeStream(); + } /** * A {@link Collector} implementation to generates a sequence from a stream of @@ -240,7 +205,7 @@ public Supplier> supplier() { @Override public BiConsumer, ITEM_TYPE> accumulator() { - return (list, value) -> list.add(value); + return List::add; } @Override @@ -253,7 +218,7 @@ public BinaryOperator> combiner() { @Override public Function, ISequence> finisher() { - return list -> of(ObjectUtils.notNull(list)); + return list -> ofCollection(ObjectUtils.notNull(list)); } @Override @@ -263,6 +228,11 @@ public Set characteristics() { }; } + @Override + default ISequence asSequence() { + return this; + } + /** * Apply the provided {@code mapFunction} to each item in the sequence. * @@ -280,107 +250,352 @@ static ISequence map( @NonNull Function mapFunction, @NonNull ISequence seq) { return seq.safeStream() - .map(item -> mapFunction.apply(item)) + .map(mapFunction::apply) .collect(toSequence()); } - @Override - default boolean contains(Object obj) { - return asList().contains(obj); - } - - @Override - default Object[] toArray() { - return asList().toArray(); - } - - @Override - default T[] toArray(T[] array) { - return asList().toArray(array); - } - - @Override - default boolean add(ITEM_TYPE item) { - throw new UnsupportedOperationException("object is immutable"); - } - - @Override - default void add(int index, ITEM_TYPE element) { - throw new UnsupportedOperationException("object is immutable"); - } - - @Override - default boolean addAll(Collection collection) { - throw new UnsupportedOperationException("object is immutable"); + /** + * Returns an unmodifiable sequence containing the provided {@code items}. + * + * @param + * the type of items contained in the sequence. + * @param items + * the items to add to the sequence + * @return the new sequence + */ + @NonNull + static ISequence ofCollection( // NOPMD - intentional + @NonNull List items) { + ISequence retval; + if (items.isEmpty()) { + retval = empty(); + } else if (items.size() == 1) { + retval = new SingletonSequence<>(ObjectUtils.notNull(items.iterator().next())); + } else { + retval = new SequenceN<>(items); + } + return retval; } - @Override - default boolean addAll(int index, Collection collection) { - throw new UnsupportedOperationException("object is immutable"); + /** + * Returns an unmodifiable sequence containing the provided {@code item}. + *

+ * If the item is {@code null} and empty sequence will be created. + * + * @param + * the type of items contained in the sequence. + * @param item + * the item to add to the sequence + * @return the new sequence + */ + @NonNull + static ISequence of( // NOPMD - intentional + @Nullable T item) { + return item == null ? empty() : new SingletonSequence<>(item); } - @Override - default boolean remove(Object obj) { - throw new UnsupportedOperationException("object is immutable"); + /** + * Returns an unmodifiable sequence containing the provided {@code items}. + * + * @param + * the type of items contained in the sequence. + * @param items + * the items to add to the sequence + * @return the new sequence + */ + // TODO: remove null check on callers + @NonNull + static ISequence of(@NonNull Stream items) { + return new StreamSequence<>(items); } - @Override - default ITEM_TYPE remove(int index) { - throw new UnsupportedOperationException("object is immutable"); + /** + * Returns an unmodifiable sequence containing zero elements. + * + * @param + * the item type + * @return an empty {@code ISequence} + */ + @NonNull + static ISequence of() { + return empty(); } - @Override - default boolean containsAll(Collection collection) { - return asList().containsAll(collection); + /** + * Returns an unmodifiable sequence containing two items. + * + * @param + * the {@code ISequence}'s item type + * @param e1 + * the first item + * @param e2 + * the second item + * @return an {@code ISequence} containing the specified items + * @throws NullPointerException + * if an item is {@code null} + */ + @NonNull + static ISequence of(T e1, T e2) { + return new SequenceN<>(e1, e2); } - @Override - default boolean removeAll(Collection collection) { - throw new UnsupportedOperationException("object is immutable"); + /** + * Returns an unmodifiable sequence containing three elements. + * + * @param + * the {@code ISequence}'s item type + * @param e1 + * the first item + * @param e2 + * the second item + * @param e3 + * the third item + * @return an {@code ISequence} containing the specified items + * @throws NullPointerException + * if an item is {@code null} + */ + @NonNull + static ISequence of(T e1, T e2, T e3) { + return new SequenceN<>(e1, e2, e3); } - @Override - default boolean retainAll(Collection collection) { - throw new UnsupportedOperationException("object is immutable"); + /** + * Returns an unmodifiable sequence containing four items. + * + * @param + * the {@code ISequence}'s item type + * @param e1 + * the first item + * @param e2 + * the second item + * @param e3 + * the third item + * @param e4 + * the fourth item + * @return an {@code ISequence} containing the specified items + * @throws NullPointerException + * if an item is {@code null} + */ + @NonNull + static ISequence of(T e1, T e2, T e3, T e4) { + return new SequenceN<>(e1, e2, e3, e4); } - @Override - default void clear() { - throw new UnsupportedOperationException("object is immutable"); + /** + * Returns an unmodifiable sequence containing five items. + * + * @param + * the {@code ISequence}'s item type + * @param e1 + * the first item + * @param e2 + * the second item + * @param e3 + * the third item + * @param e4 + * the fourth item + * @param e5 + * the fifth item + * @return an {@code ISequence} containing the specified items + * @throws NullPointerException + * if an item is {@code null} + */ + @NonNull + static ISequence of(T e1, T e2, T e3, T e4, T e5) { + return new SequenceN<>(e1, e2, e3, e4, e5); } - @Override - default ITEM_TYPE get(int index) { - return asList().get(index); + /** + * Returns an unmodifiable sequence containing six items. + * + * @param + * the {@code ISequence}'s item type + * @param e1 + * the first item + * @param e2 + * the second item + * @param e3 + * the third item + * @param e4 + * the fourth item + * @param e5 + * the fifth item + * @param e6 + * the sixth item + * @return an {@code ISequence} containing the specified items + * @throws NullPointerException + * if an item is {@code null} + */ + @NonNull + static ISequence of(T e1, T e2, T e3, T e4, T e5, T e6) { + return new SequenceN<>(e1, e2, e3, e4, e5, e6); } - @Override - default ITEM_TYPE set(int index, ITEM_TYPE element) { - throw new UnsupportedOperationException("object is immutable"); + /** + * Returns an unmodifiable sequence containing seven items. + * + * @param + * the {@code ISequence}'s item type + * @param e1 + * the first item + * @param e2 + * the second item + * @param e3 + * the third item + * @param e4 + * the fourth item + * @param e5 + * the fifth item + * @param e6 + * the sixth item + * @param e7 + * the seventh item + * @return an {@code ISequence} containing the specified items + * @throws NullPointerException + * if an item is {@code null} + */ + @NonNull + static ISequence of(T e1, T e2, T e3, T e4, T e5, T e6, T e7) { + return new SequenceN<>(e1, e2, e3, e4, e5, e6, e7); } - @Override - default int indexOf(Object obj) { - return asList().indexOf(obj); + /** + * Returns an unmodifiable sequence containing eight items. + * + * @param + * the {@code ISequence}'s item type + * @param e1 + * the first item + * @param e2 + * the second item + * @param e3 + * the third item + * @param e4 + * the fourth item + * @param e5 + * the fifth item + * @param e6 + * the sixth item + * @param e7 + * the seventh item + * @param e8 + * the eighth item + * @return an {@code ISequence} containing the specified items + * @throws NullPointerException + * if an item is {@code null} + */ + @NonNull + static ISequence of(T e1, T e2, T e3, T e4, T e5, T e6, T e7, T e8) { + return new SequenceN<>(e1, e2, e3, e4, e5, e6, e7, e8); } - @Override - default int lastIndexOf(Object obj) { - return asList().lastIndexOf(obj); + /** + * Returns an unmodifiable sequence containing nine items. + * + * @param + * the {@code ISequence}'s item type + * @param e1 + * the first item + * @param e2 + * the second item + * @param e3 + * the third item + * @param e4 + * the fourth item + * @param e5 + * the fifth item + * @param e6 + * the sixth item + * @param e7 + * the seventh item + * @param e8 + * the eighth item + * @param e9 + * the ninth item + * @return an {@code ISequence} containing the specified items + * @throws NullPointerException + * if an item is {@code null} + */ + @NonNull + static ISequence of(T e1, T e2, T e3, T e4, T e5, T e6, T e7, T e8, T e9) { + return new SequenceN<>(e1, e2, e3, e4, e5, e6, e7, e8, e9); } - @Override - default ListIterator listIterator() { - return asList().listIterator(); + /** + * Returns an unmodifiable sequence containing ten items. + * + * @param + * the {@code ISequence}'s item type + * @param e1 + * the first item + * @param e2 + * the second item + * @param e3 + * the third item + * @param e4 + * the fourth item + * @param e5 + * the fifth item + * @param e6 + * the sixth item + * @param e7 + * the seventh item + * @param e8 + * the eighth item + * @param e9 + * the ninth item + * @param e10 + * the tenth item + * @return an {@code IArrayItem} containing the specified items + * @throws NullPointerException + * if an item is {@code null} + */ + @NonNull + static ISequence of(T e1, T e2, T e3, T e4, T e5, T e6, T e7, T e8, T e9, T e10) { + return new SequenceN<>(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10); } - @Override - default ListIterator listIterator(int index) { - return asList().listIterator(index); + /** + * Returns an unmodifiable sequence containing an arbitrary number of items. + * + * @param + * the {@code ISequence}'s item type + * @param items + * the items to be contained in the list + * @return an {@code ISequence} containing the specified items + * @throws NullPointerException + * if an item is {@code null} or if the array is {@code null} + */ + @SafeVarargs + @NonNull + static ISequence of(@NonNull T... items) { + return items.length == 0 ? empty() : new SequenceN<>(items); } - @Override - default List subList(int fromIndex, int toIndex) { - return asList().subList(fromIndex, toIndex); + /** + * Returns an unmodifiable sequence containing the items of the given + * Collection, in its iteration order. The given Collection must not be null, + * and it must not contain any null items. If the given Collection is + * subsequently modified, the returned array item will not reflect such + * modifications. + * + * @param + * the {@code ISequence}'s item type + * @param collection + * a {@code Collection} from which items are drawn, must be non-null + * @return an {@code ISequence} containing the items of the given + * {@code Collection} + * @throws NullPointerException + * if collection is null, or if it contains any nulls + * @since 10 + */ + @SuppressWarnings("unchecked") + @NonNull + static ISequence copyOf(Collection collection) { + return collection instanceof IArrayItem + ? (ISequence) collection + : collection.isEmpty() + ? empty() + : new SequenceN<>(new ArrayList<>(collection)); } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/InvalidTypeMetapathException.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/InvalidTypeMetapathException.java index f7ace0bbf..b08d9f5a3 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/InvalidTypeMetapathException.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/InvalidTypeMetapathException.java @@ -56,7 +56,7 @@ public class InvalidTypeMetapathException * the original exception cause */ public InvalidTypeMetapathException(@NonNull IItem item, @NonNull Throwable cause) { - super(TypeMetapathException.INVALID_TYPE_ERROR, String.format("Invalid data type '%s'", item.getClass().getName()), + super(INVALID_TYPE_ERROR, String.format("Invalid data type '%s'", item.getClass().getName()), cause); this.item = item; } @@ -69,7 +69,7 @@ public InvalidTypeMetapathException(@NonNull IItem item, @NonNull Throwable caus * the item related to the invalid type error */ public InvalidTypeMetapathException(@NonNull IItem item) { - super(TypeMetapathException.INVALID_TYPE_ERROR, String.format("Invalid data type '%s'", item.getClass().getName())); + super(INVALID_TYPE_ERROR, String.format("Invalid data type '%s'", item.getClass().getName())); this.item = item; } @@ -85,7 +85,7 @@ public InvalidTypeMetapathException(@NonNull IItem item) { * the original exception cause */ public InvalidTypeMetapathException(@Nullable IItem item, @Nullable String message, @NonNull Throwable cause) { - super(TypeMetapathException.INVALID_TYPE_ERROR, message, cause); + super(INVALID_TYPE_ERROR, message, cause); this.item = item; } @@ -99,7 +99,7 @@ public InvalidTypeMetapathException(@Nullable IItem item, @Nullable String messa * the exception message */ public InvalidTypeMetapathException(@Nullable IItem item, @Nullable String message) { - super(TypeMetapathException.INVALID_TYPE_ERROR, message); + super(INVALID_TYPE_ERROR, message); this.item = item; } 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 86b73dd12..1ddc29efb 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 @@ -50,21 +50,30 @@ public final class MetapathConstants { URI.create("http://csrc.nist.gov/ns/metaschema/metapath-functions")); @NonNull public static final URI NS_METAPATH_FUNCTIONS_MATH = ObjectUtils.requireNonNull( - URI.create("http://csrc.nist.gov/ns/metaschema/metapath-functions/math")); + URI.create(NS_METAPATH_FUNCTIONS + "/math")); @NonNull - public static final URI NS_METAPATH_FUNCTIONS_EXTENDED = NS_METAPATH; + public static final URI NS_METAPATH_FUNCTIONS_ARRAY = ObjectUtils.requireNonNull( + URI.create(NS_METAPATH_FUNCTIONS + "/array")); + @NonNull + public static final URI NS_METAPATH_FUNCTIONS_MAP = ObjectUtils.requireNonNull( + URI.create(NS_METAPATH_FUNCTIONS + "/map")); + @NonNull + public static final URI NS_METAPATH_FUNCTIONS_EXTENDED = NS_METAPATH_FUNCTIONS; @NonNull - public static final String PREFIX_METAPATH = "mp"; + public static final String PREFIX_METAPATH = "meta"; @NonNull public static final String PREFIX_XML_SCHEMA = "xs"; @NonNull public static final String PREFIX_XPATH_FUNCTIONS = "mp"; @NonNull public static final String PREFIX_XPATH_FUNCTIONS_MATH = "math"; + @NonNull + public static final String PREFIX_XPATH_FUNCTIONS_ARRAY = "array"; + @NonNull + public static final String PREFIX_XPATH_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 15d1674aa..7d2fff298 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 @@ -46,6 +46,8 @@ import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonTokenStream; +import org.antlr.v4.runtime.DefaultErrorStrategy; +import org.antlr.v4.runtime.Parser; import org.antlr.v4.runtime.misc.ParseCancellationException; import org.antlr.v4.runtime.tree.ParseTree; import org.apache.logging.log4j.LogManager; @@ -88,17 +90,25 @@ public enum ResultType { /** * The result is expected to be an {@link INodeItem} value. */ - NODE; + // TODO: audit use of this value, replace with ITEM where appropriate + NODE, + /** + * The result is expected to be an {@link IItem} value. + */ + ITEM; } private static final Logger LOGGER = LogManager.getLogger(MetapathExpression.class); @NonNull - public static final MetapathExpression CONTEXT_NODE = new MetapathExpression(".", ContextItem.instance()); + public static final MetapathExpression CONTEXT_NODE + = new MetapathExpression(".", ContextItem.instance(), StaticContext.instance()); private final String path; @NonNull - private final IExpression node; + private final IExpression expression; + @NonNull + private final StaticContext staticContext; /** * Compiles a Metapath expression string. @@ -111,6 +121,24 @@ public enum ResultType { */ @NonNull public static MetapathExpression compile(@NonNull String path) { + StaticContext context = StaticContext.builder().build(); + + return compile(path, context); + } + + /** + * Compiles a Metapath expression string using the provided static context. + * + * @param path + * the metapath expression + * @param context + * the static evaluation context + * @return the compiled expression object + * @throws MetapathException + * if an error occurred while compiling the Metapath expression + */ + @NonNull + public static MetapathExpression compile(@NonNull String path, @NonNull StaticContext context) { @NonNull MetapathExpression retval; if (".".equals(path)) { retval = CONTEXT_NODE; @@ -124,6 +152,13 @@ public static MetapathExpression compile(@NonNull String path) { Metapath10 parser = new Metapath10(tokens); parser.removeErrorListeners(); parser.addErrorListener(new FailingErrorListener()); + parser.setErrorHandler(new DefaultErrorStrategy() { + + @Override + public void sync(Parser recognizer) { + // disable + } + }); ParseTree tree = ObjectUtils.notNull(parser.expr()); @@ -140,12 +175,12 @@ public static MetapathExpression compile(@NonNull String path) { } } - IExpression expr = new BuildCSTVisitor().visit(tree); + IExpression expr = new BuildCSTVisitor(context).visit(tree); if (LOGGER.isDebugEnabled()) { LOGGER.atDebug().log(String.format("Metapath CST:%n%s", CSTPrinter.toString(expr))); } - retval = new MetapathExpression(path, expr); + retval = new MetapathExpression(path, expr, context); } catch (MetapathException | ParseCancellationException ex) { String msg = String.format("Unable to compile Metapath '%s'", path); LOGGER.atError().withThrowable(ex).log(msg); @@ -162,10 +197,13 @@ public static MetapathExpression compile(@NonNull String path) { * the Metapath as a string * @param expr * the Metapath as a compiled abstract syntax tree (AST) + * @param staticContext + * the static evaluation context */ - protected MetapathExpression(@NonNull String path, @NonNull IExpression expr) { + protected MetapathExpression(@NonNull String path, @NonNull IExpression expr, @NonNull StaticContext staticContext) { this.path = path; - this.node = expr; + this.expression = expr; + this.staticContext = staticContext; } /** @@ -184,7 +222,22 @@ public String getPath() { */ @NonNull protected IExpression getASTNode() { - return node; + return expression; + } + + @NonNull + protected StaticContext getStaticContext() { + return staticContext; + } + + /** + * Generate a new dynamic context. + * + * @return the generated dynamic context + */ + @NonNull + public DynamicContext dynamicContext() { + return new DynamicContext(getStaticContext()); } @Override @@ -306,8 +359,9 @@ protected T toResultType(@NonNull ISequence sequence, @NonNull ResultType case BOOLEAN: result = FnBoolean.fnBoolean(sequence).toBoolean(); break; + case ITEM: case NODE: - result = FunctionUtils.getFirstItem(sequence, true); + result = sequence.getFirstItem(true); break; case NUMBER: INumericItem numeric = FunctionUtils.toNumeric(sequence, true); @@ -317,8 +371,8 @@ protected T toResultType(@NonNull ISequence sequence, @NonNull ResultType result = sequence; break; case STRING: - IItem item = FunctionUtils.getFirstItem(sequence, true); - result = item == null ? "" : FnData.fnDataItem(item).asString(); + 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())); @@ -360,10 +414,7 @@ public ISequence evaluate() { @NonNull public ISequence evaluate( @Nullable IItem focus) { - return (ISequence) evaluate( - focus, - StaticContext.builder() - .build().dynamicContext()); + return (ISequence) evaluate(focus, dynamicContext()); } /** 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 c30b41349..10794c9df 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 @@ -26,11 +26,15 @@ package gov.nist.secauto.metaschema.core.metapath; +import gov.nist.secauto.metaschema.core.metapath.EQNameUtils.IEQNamePrefixResolver; import gov.nist.secauto.metaschema.core.util.CollectionUtil; import java.net.URI; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +import javax.xml.XMLConstants; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; @@ -44,6 +48,8 @@ public final class StaticContext { @NonNull private static final Map WELL_KNOWN_NAMESPACES; + @NonNull + private static final Map WELL_KNOWN_URI_TO_PREFIX; static { Map knownNamespaces = new ConcurrentHashMap<>(); @@ -59,13 +65,29 @@ public final class StaticContext { knownNamespaces.put( MetapathConstants.PREFIX_XPATH_FUNCTIONS_MATH, MetapathConstants.NS_METAPATH_FUNCTIONS_MATH); + knownNamespaces.put( + MetapathConstants.PREFIX_XPATH_FUNCTIONS_ARRAY, + MetapathConstants.NS_METAPATH_FUNCTIONS_ARRAY); + knownNamespaces.put( + MetapathConstants.PREFIX_XPATH_FUNCTIONS_MAP, + MetapathConstants.NS_METAPATH_FUNCTIONS_MAP); WELL_KNOWN_NAMESPACES = CollectionUtil.unmodifiableMap(knownNamespaces); + + WELL_KNOWN_URI_TO_PREFIX = WELL_KNOWN_NAMESPACES.entrySet().stream() + .collect(Collectors.toUnmodifiableMap( + entry -> entry.getValue().toASCIIString(), + Map.Entry::getKey, + (v1, v2) -> v2)); } @Nullable private final URI baseUri; @NonNull private final Map knownNamespaces; + @Nullable + private final URI defaultModelNamespace; + @Nullable + private final URI defaultFunctionNamespace; /** * Get the mapping of prefix to namespace URI for all well-known namespaces @@ -81,6 +103,22 @@ public static Map getWellKnownNamespaces() { return WELL_KNOWN_NAMESPACES; } + /** + * Get the mapping of namespace URIs to prefixes for all well-known namespaces + * provided by default to the static context. + * + * @return the mapping of namespace URI to prefix for all well-known namespaces + */ + @SuppressFBWarnings("MS_EXPOSE_REP") + public static Map getWellKnownURIToPrefix() { + return WELL_KNOWN_URI_TO_PREFIX; + } + + @Nullable + public static String getWellKnownPrefixForUri(String uri) { + return WELL_KNOWN_URI_TO_PREFIX.get(uri); + } + /** * Create a new static context instance using default values. * @@ -102,11 +140,11 @@ public static Builder builder() { return new Builder(); } - private StaticContext( - @Nullable URI baseUri, - @NonNull Map knownNamespaces) { - this.baseUri = baseUri; - this.knownNamespaces = knownNamespaces; + private StaticContext(Builder builder) { + this.baseUri = builder.baseUri; + this.knownNamespaces = CollectionUtil.unmodifiableMap(Map.copyOf(builder.namespaces)); + this.defaultModelNamespace = builder.defaultModelNamespace; + this.defaultFunctionNamespace = builder.defaultFunctionNamespace; } /** @@ -167,22 +205,93 @@ public String lookupNamespaceForPrefix(@NonNull String prefix) { } /** - * Generate a new dynamic context. + * Get the default namespace for assembly, field, or flag references that have + * no namespace prefix. + * + * @return the namespace if defined or {@code null} otherwise + */ + @Nullable + public URI getDefaultModelNamespace() { + return defaultModelNamespace; + } + + /** + * Get the default namespace for function references that have no namespace + * prefix. * - * @return the generated dynamic context + * @return the namespace if defined or {@code null} otherwise */ + @Nullable + public URI getDefaultFunctionNamespace() { + return defaultFunctionNamespace; + } + + @NonNull + public IEQNamePrefixResolver getFunctionPrefixResolver() { + return (prefix) -> { + String ns = lookupNamespaceForPrefix(prefix); + if (ns == null) { + URI uri = getDefaultFunctionNamespace(); + if (uri != null) { + ns = uri.toASCIIString(); + } + } + return ns == null ? XMLConstants.NULL_NS_URI : ns; + }; + } + + @NonNull + public IEQNamePrefixResolver getFlagPrefixResolver() { + return (prefix) -> { + String ns = lookupNamespaceForPrefix(prefix); + return ns == null ? XMLConstants.NULL_NS_URI : ns; + }; + } + + @NonNull + public IEQNamePrefixResolver getModelPrefixResolver() { + return (prefix) -> { + String ns = lookupNamespaceForPrefix(prefix); + if (ns == null) { + URI uri = getDefaultModelNamespace(); + if (uri != null) { + ns = uri.toASCIIString(); + } + } + return ns == null ? XMLConstants.NULL_NS_URI : ns; + }; + } + + @NonNull + public IEQNamePrefixResolver getVariablePrefixResolver() { + return (prefix) -> { + String ns = lookupNamespaceForPrefix(prefix); + return ns == null ? XMLConstants.NULL_NS_URI : ns; + }; + } + @NonNull - public DynamicContext dynamicContext() { - return new DynamicContext(this); + public Builder buildFrom() { + Builder builder = new Builder(); + builder.baseUri = this.baseUri; + builder.namespaces.putAll(this.knownNamespaces); + builder.defaultModelNamespace = this.defaultModelNamespace; + builder.defaultFunctionNamespace = this.defaultFunctionNamespace; + return builder; } /** * A builder used to generate the static context. */ public static final class Builder { + @Nullable private URI baseUri; @NonNull private final Map namespaces = new ConcurrentHashMap<>(); + @Nullable + private URI defaultModelNamespace; + @Nullable + private URI defaultFunctionNamespace = MetapathConstants.NS_METAPATH_FUNCTIONS; private Builder() { namespaces.put( @@ -240,6 +349,85 @@ public Builder namespace(@NonNull String prefix, @NonNull URI uri) { return this; } + /** + * A convenience method for {@link #namespace(String, URI)}. + * + * @param prefix + * the prefix to associate with the namespace, which may be + * @param uri + * the namespace URI + * @return this builder + * @throws IllegalArgumentException + * if the provided URI is invalid + * @see StaticContext#lookupNamespaceForPrefix(String) + * @see StaticContext#lookupNamespaceURIForPrefix(String) + * @see StaticContext#getWellKnownNamespaces() + */ + @NonNull + public Builder namespace(@NonNull String prefix, @NonNull String uri) { + return namespace(prefix, URI.create(uri)); + } + + /** + * Defines the default namespace to use for assembly, field, or flag references + * that have no namespace prefix. + * + * @param uri + * the namespace URI + * @return this builder + * @see StaticContext#getDefaultModelNamespace() + */ + @NonNull + public Builder defaultModelNamespace(@NonNull URI uri) { + this.defaultModelNamespace = uri; + return this; + } + + /** + * A convenience method for {@link #defaultModelNamespace(URI)}. + * + * @param uri + * the namespace URI + * @return this builder + * @throws IllegalArgumentException + * if the provided URI is invalid + * @see StaticContext#getDefaultModelNamespace() + */ + @NonNull + public Builder defaultModelNamespace(@NonNull String uri) { + return defaultModelNamespace(URI.create(uri)); + } + + /** + * Defines the default namespace to use for assembly, field, or flag references + * that have no namespace prefix. + * + * @param uri + * the namespace URI + * @return this builder + * @see StaticContext#getDefaultFunctionNamespace() + */ + @NonNull + public Builder defaultFunctionNamespace(@NonNull URI uri) { + this.defaultFunctionNamespace = uri; + return this; + } + + /** + * A convenience method for {@link #defaultFunctionNamespace(URI)}. + * + * @param uri + * the namespace URI + * @return this builder + * @throws IllegalArgumentException + * if the provided URI is invalid + * @see StaticContext#getDefaultFunctionNamespace() + */ + @NonNull + public Builder defaultFunctionNamespace(@NonNull String uri) { + return defaultFunctionNamespace(URI.create(uri)); + } + /** * Construct a new static context using the information provided to the builder. * @@ -247,9 +435,7 @@ public Builder namespace(@NonNull String prefix, @NonNull URI uri) { */ @NonNull public StaticContext build() { - return new StaticContext( - baseUri, - CollectionUtil.unmodifiableMap(namespaces)); + return new StaticContext(this); } } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/StaticMetapathException.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/StaticMetapathException.java index eea69c7a7..0331a3cff 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/StaticMetapathException.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/StaticMetapathException.java @@ -129,7 +129,7 @@ public StaticMetapathException(int code, Throwable cause) { } @Override - protected String getCodePrefix() { + public String getCodePrefix() { return "MPST"; } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/TypeMetapathException.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/TypeMetapathException.java index 89de22791..9066b5976 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/TypeMetapathException.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/TypeMetapathException.java @@ -106,7 +106,7 @@ public TypeMetapathException(int code, Throwable cause) { } @Override - protected String getCodePrefix() { + public String getCodePrefix() { return "MPTY"; } } 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 3b3d16983..a6719255c 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 @@ -32,11 +32,14 @@ import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.AndexprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ArgumentContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ArgumentlistContext; +import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ArrayconstructorContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ArrowexprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ArrowfunctionspecifierContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.AxisstepContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ComparisonexprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ContextitemexprContext; +import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.CurlyarrayconstructorContext; +import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.EnclosedexprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.EqnameContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ExprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ExprsingleContext; @@ -47,8 +50,14 @@ import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.GeneralcompContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.IfexprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.IntersectexceptexprContext; +import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.KeyspecifierContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.LetexprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.LiteralContext; +import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.LookupContext; +import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.MapconstructorContext; +import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.MapconstructorentryContext; +import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.MapkeyexprContext; +import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.MapvalueexprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.MetapathContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.MultiplicativeexprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.NametestContext; @@ -71,9 +80,11 @@ import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.SimpleletbindingContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.SimpleletclauseContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.SimplemapexprContext; +import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.SquarearrayconstructorContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.StepexprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.StringconcatexprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.UnaryexprContext; +import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.UnarylookupContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.UnionexprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ValuecompContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ValueexprContext; @@ -138,10 +149,9 @@ protected R delegateToChild(@NonNull T ctx) { throw new IllegalStateException("a single child expression was expected"); } - /* ============================================================ - * Expressions - https://www.w3.org/TR/xpath-31/#id-expressions - * ============================================================ - */ + // ============================================================ + // Expressions - https://www.w3.org/TR/xpath-31/#id-expressions + // ============================================================ @Override public R visitMetapath(MetapathContext ctx) { @@ -169,10 +179,10 @@ public R visitExprsingle(ExprsingleContext ctx) { assert ctx != null; return delegateToChild(ctx); } - /* ============================================================================ - * Primary Expressions - https://www.w3.org/TR/xpath-31/#id-primary-expressions - * ============================================================================ - */ + + // ============================================================================ + // Primary Expressions - https://www.w3.org/TR/xpath-31/#id-primary-expressions + // ============================================================================ @Override public R visitPrimaryexpr(PrimaryexprContext ctx) { @@ -180,10 +190,9 @@ public R visitPrimaryexpr(PrimaryexprContext ctx) { return delegateToChild(ctx); } - /* ================================================================= - * Literal Expressions - https://www.w3.org/TR/xpath-31/#id-literals - * ================================================================= - */ + // ================================================================= + // Literal Expressions - https://www.w3.org/TR/xpath-31/#id-literals + // ================================================================= /** * Handle the provided expression. @@ -215,10 +224,9 @@ public R visitNumericliteral(NumericliteralContext ctx) { return handle(ctx, (context) -> handleNumericLiteral(ctx)); } - /* ================================================================== - * Variable References - https://www.w3.org/TR/xpath-31/#id-variables - * ================================================================== - */ + // ================================================================== + // Variable References - https://www.w3.org/TR/xpath-31/#id-variables + // ================================================================== /** * Handle the provided expression. @@ -241,10 +249,10 @@ public R visitVarname(VarnameContext ctx) { return delegateToChild(ctx); } - /* ================================================================================= - * Parenthesized Expressions - https://www.w3.org/TR/xpath-31/#id-paren-expressions - * ================================================================================= - */ + // ==================================================== + // Parenthesized Expressions - + // https://www.w3.org/TR/xpath-31/#id-paren-expressions + // ==================================================== /** * Handle the provided expression. @@ -262,10 +270,10 @@ public R visitParenthesizedexpr(ParenthesizedexprContext ctx) { return expr == null ? handleEmptyParenthesizedexpr(ctx) : visit(expr); } - /* ===================================================================================== - * Context Item Expression - https://www.w3.org/TR/xpath-31/#id-context-item-expression - * ===================================================================================== - */ + // ========================================================== + // Context Item Expression - + // https://www.w3.org/TR/xpath-31/#id-context-item-expression + // ========================================================== /** * Handle the provided expression. @@ -282,10 +290,9 @@ public R visitContextitemexpr(ContextitemexprContext ctx) { return handle(ctx, (context) -> handleContextitemexpr(ctx)); } - /* ========================================================================= - * Static Function Calls - https://www.w3.org/TR/xpath-31/#id-function-calls - * ========================================================================= - */ + // ========================================================================= + // Static Function Calls - https://www.w3.org/TR/xpath-31/#id-function-calls + // ========================================================================= /** * Handle the provided expression. @@ -314,10 +321,19 @@ public R visitArgument(ArgumentContext ctx) { throw new IllegalStateException(); } - /* ========================================================================= - * Filter Expressions - https://www.w3.org/TR/xpath-31/#id-filter-expression - * ========================================================================= - */ + // ======================================================================= + // Enclosed Expressions - https://www.w3.org/TR/xpath-31/#id-enclosed-expr + // ======================================================================= + + @Override + public R visitEnclosedexpr(EnclosedexprContext ctx) { + ExprContext expr = ctx.expr(); + return expr == null ? null : expr.accept(this); + } + + // ========================================================================= + // Filter Expressions - https://www.w3.org/TR/xpath-31/#id-filter-expression + // ========================================================================= /** * Handle the provided expression. @@ -334,16 +350,39 @@ public R visitPostfixexpr(PostfixexprContext ctx) { return handle(ctx, (context) -> handlePostfixexpr(ctx)); } + /** + * Handle the provided expression. + * + * @param ctx + * the provided expression context + * @return the result + */ + protected abstract R handlePredicate(@NonNull PredicateContext ctx); + @Override public R visitPredicate(PredicateContext ctx) { - // should never be called, since this is handled by the parent expression - throw new IllegalStateException(); + assert ctx != null; + return handlePredicate(ctx); } - /* ====================================================================== - * Path Expressions - https://www.w3.org/TR/xpath-31/#id-path-expressions - * ====================================================================== + /** + * Handle the provided expression. + * + * @param ctx + * the provided expression context + * @return the result */ + protected abstract R handleLookup(@NonNull LookupContext ctx); + + @Override + public R visitLookup(LookupContext ctx) { + assert ctx != null; + return handleLookup(ctx); + } + + // ====================================================================== + // Path Expressions - https://www.w3.org/TR/xpath-31/#id-path-expressions + // ====================================================================== /** * Handle the provided expression. @@ -360,10 +399,10 @@ public R visitPathexpr(PathexprContext ctx) { return handle(ctx, (context) -> handlePathexpr(ctx)); } - /* ======================================================================================= - * RelativePath Expressions - https://www.w3.org/TR/xpath-31/#id-relative-path-expressions - * ======================================================================================= - */ + // ============================================================ + // RelativePath Expressions - + // https://www.w3.org/TR/xpath-31/#id-relative-path-expressions + // ============================================================ /** * Handle the provided expression. @@ -380,10 +419,9 @@ public R visitRelativepathexpr(RelativepathexprContext ctx) { return handle(ctx, (context) -> handleRelativepathexpr(ctx)); } - /* ================================================ - * Steps - https://www.w3.org/TR/xpath-31/#id-steps - * ================================================ - */ + // ================================================ + // Steps - https://www.w3.org/TR/xpath-31/#id-steps + // ================================================ @Override public R visitStepexpr(StepexprContext ctx) { @@ -423,10 +461,9 @@ public R visitReversestep(ReversestepContext ctx) { return handle(ctx, (context) -> handleReversestep(ctx)); } - /* ====================================================================== - * Predicates within Steps - https://www.w3.org/TR/xpath-31/#id-predicate - * ====================================================================== - */ + // ====================================================================== + // Predicates within Steps - https://www.w3.org/TR/xpath-31/#id-predicate + // ====================================================================== /** * Handle the provided expression. @@ -449,10 +486,9 @@ public R visitPredicatelist(PredicatelistContext ctx) { throw new IllegalStateException(); } - /* =========================================== - * Axes - https://www.w3.org/TR/xpath-31/#axes - * =========================================== - */ + // =========================================== + // Axes - https://www.w3.org/TR/xpath-31/#axes + // =========================================== @Override public R visitForwardaxis(ForwardaxisContext ctx) { @@ -466,37 +502,26 @@ public R visitReverseaxis(ReverseaxisContext ctx) { throw new IllegalStateException(); } - /* ======================================================= - * Node Tests - https://www.w3.org/TR/xpath-31/#node-tests - * ======================================================= - */ + // ======================================================= + // Node Tests - https://www.w3.org/TR/xpath-31/#node-tests + // ======================================================= @Override public R visitNodetest(NodetestContext ctx) { - // TODO: revisit once kindtest is implemented - assert ctx != null; - return delegateToChild(ctx); + // should never be called, since this is handled by the calling context + throw new IllegalStateException(); } @Override public R visitNametest(NametestContext ctx) { - assert ctx != null; - return delegateToChild(ctx); + // should never be called, since this is handled by the calling context + throw new IllegalStateException(); } - /** - * Handle the provided expression. - * - * @param ctx - * the provided expression context - * @return the result - */ - protected abstract R handleEqname(@NonNull EqnameContext ctx); - @Override public R visitEqname(EqnameContext ctx) { - assert ctx != null; - return handleEqname(ctx); + // should never be called, since this is handled by the calling context + throw new IllegalStateException(); } /** @@ -514,10 +539,9 @@ public R visitWildcard(WildcardContext ctx) { return handleWildcard(ctx); } - /* =========================================================== - * Abbreviated Syntax - https://www.w3.org/TR/xpath-31/#abbrev - * =========================================================== - */ + // =========================================================== + // Abbreviated Syntax - https://www.w3.org/TR/xpath-31/#abbrev + // =========================================================== /** * Handle the provided expression. @@ -549,10 +573,9 @@ public R visitAbbrevreversestep(AbbrevreversestepContext ctx) { return handleAbbrevreversestep(ctx); } - /* ====================================================================== - * Constructing Sequences - https://www.w3.org/TR/xpath-31/#construct_seq - * ====================================================================== - */ + // ====================================================================== + // Constructing Sequences - https://www.w3.org/TR/xpath-31/#construct_seq + // ====================================================================== /** * Handle the provided expression. @@ -569,10 +592,9 @@ public R visitRangeexpr(RangeexprContext ctx) { return handle(ctx, (context) -> handleRangeexpr(ctx)); } - /* ======================================================================== - * Combining Node Sequences - https://www.w3.org/TR/xpath-31/#combining_seq - * ======================================================================== - */ + // ======================================================================== + // Combining Node Sequences - https://www.w3.org/TR/xpath-31/#combining_seq + // ======================================================================== /** * Handle the provided expression. @@ -604,10 +626,9 @@ public R visitIntersectexceptexpr(IntersectexceptexprContext ctx) { return handle(ctx, (context) -> handleIntersectexceptexpr(ctx)); } - /* ====================================================================== - * Arithmetic Expressions - https://www.w3.org/TR/xpath-31/#id-arithmetic - * ====================================================================== - */ + // ====================================================================== + // Arithmetic Expressions - https://www.w3.org/TR/xpath-31/#id-arithmetic + // ====================================================================== /** * Handle the provided expression. @@ -660,10 +681,10 @@ public R visitValueexpr(ValueexprContext ctx) { return delegateToChild(ctx); } - /* ======================================================================================== - * String Concatenation Expressions - https://www.w3.org/TR/xpath-31/#id-string-concat-expr - * ======================================================================================== - */ + // ===================================================== + // String Concatenation Expressions - + // https://www.w3.org/TR/xpath-31/#id-string-concat-expr + // ===================================================== /** * Handle the provided expression. @@ -680,10 +701,9 @@ public R visitStringconcatexpr(StringconcatexprContext ctx) { return handle(ctx, (context) -> handleStringconcatexpr(ctx)); } - /* ======================================================================= - * Comparison Expressions - https://www.w3.org/TR/xpath-31/#id-comparisons - * ======================================================================= - */ + // ======================================================================= + // Comparison Expressions - https://www.w3.org/TR/xpath-31/#id-comparisons + // ======================================================================= /** * Handle the provided expression. @@ -712,10 +732,9 @@ public R visitGeneralcomp(GeneralcompContext ctx) { throw new IllegalStateException(); } - /* ============================================================================ - * Logical Expressions - https://www.w3.org/TR/xpath-31/#id-logical-expressions - * ============================================================================ - */ + // ============================================================================ + // Logical Expressions - https://www.w3.org/TR/xpath-31/#id-logical-expressions + // ============================================================================ /** * Handle the provided expression. @@ -747,10 +766,9 @@ public R visitAndexpr(AndexprContext ctx) { return handle(ctx, (context) -> handleAndexpr(ctx)); } - /* ==================================================================== - * For Expressions - https://www.w3.org/TR/xpath-31/#id-for-expressions - * ==================================================================== - */ + // ==================================================================== + // For Expressions - https://www.w3.org/TR/xpath-31/#id-for-expressions + // ==================================================================== /** * Handle the provided expression. @@ -779,10 +797,9 @@ public R visitSimpleforbinding(SimpleforbindingContext ctx) { throw new IllegalStateException(); } - /* ==================================================================== - * Let Expressions - https://www.w3.org/TR/xpath-31/#id-let-expressions - * ==================================================================== - */ + // ==================================================================== + // Let Expressions - https://www.w3.org/TR/xpath-31/#id-let-expressions + // ==================================================================== /** * Handle the provided expression. @@ -811,10 +828,107 @@ public R visitSimpleletbinding(SimpleletbindingContext ctx) { throw new IllegalStateException(); } - /* ========================================================================= - * Conditional Expressions - https://www.w3.org/TR/xpath-31/#id-conditionals - * ========================================================================= + // ====================================================================== + // Map Constructors - https://www.w3.org/TR/xpath-31/#id-map-constructors + // ====================================================================== + + /** + * Handle the provided expression. + * + * @param ctx + * the provided expression context + * @return the result + */ + protected abstract R handleMapConstructor(@NonNull MapconstructorContext ctx); + + @Override + public R visitMapconstructor(MapconstructorContext ctx) { + assert ctx != null; + return handleMapConstructor(ctx); + } + + @Override + public R visitMapconstructorentry(MapconstructorentryContext ctx) { + // should never be called, since this is handled by the parent expression + throw new IllegalStateException(); + } + + @Override + public R visitMapkeyexpr(MapkeyexprContext ctx) { + assert ctx != null; + return delegateToChild(ctx); + } + + @Override + public R visitMapvalueexpr(MapvalueexprContext ctx) { + assert ctx != null; + return delegateToChild(ctx); + } + + // ============================================================== + // Array Constructors - https://www.w3.org/TR/xpath-31/#id-arrays + // ============================================================== + + @Override + public R visitArrayconstructor(ArrayconstructorContext ctx) { + assert ctx != null; + return delegateToChild(ctx); + } + + /** + * Handle the provided expression. + * + * @param ctx + * the provided expression context + * @return the result + */ + protected abstract R handleArrayConstructor(@NonNull SquarearrayconstructorContext ctx); + + /** + * Handle the provided expression. + * + * @param ctx + * the provided expression context + * @return the result + */ + protected abstract R handleArrayConstructor(@NonNull CurlyarrayconstructorContext ctx); + + @Override + public R visitSquarearrayconstructor(SquarearrayconstructorContext ctx) { + assert ctx != null; + return handleArrayConstructor(ctx); + } + + @Override + public R visitCurlyarrayconstructor(CurlyarrayconstructorContext ctx) { + assert ctx != null; + return handleArrayConstructor(ctx); + } + + @Override + public R visitKeyspecifier(KeyspecifierContext ctx) { + // should never be called, since this is handled by the parent expression + throw new IllegalStateException(); + } + + /** + * Handle the provided expression. + * + * @param ctx + * the provided expression context + * @return the result */ + protected abstract R handleUnarylookup(@NonNull UnarylookupContext ctx); + + @Override + public R visitUnarylookup(UnarylookupContext ctx) { + assert ctx != null; + return handleUnarylookup(ctx); + } + + // ========================================================================= + // Conditional Expressions - https://www.w3.org/TR/xpath-31/#id-conditionals + // ========================================================================= /** * Handle the provided expression. @@ -831,9 +945,12 @@ public R visitIfexpr(IfexprContext ctx) { return handle(ctx, (context) -> handleIfexpr(ctx)); } - /* ================================================================================== - * Quantified Expressions - https://www.w3.org/TR/xpath-31/#id-quantified-expressions - * ================================================================================== + /* + * ============================================================================= + * ===== Quantified Expressions - + * https://www.w3.org/TR/xpath-31/#id-quantified-expressions + * ============================================================================= + * ===== */ /** @@ -851,7 +968,8 @@ public R visitQuantifiedexpr(QuantifiedexprContext ctx) { return handleQuantifiedexpr(ctx); } - /* ========================================================================= + /* + * ========================================================================= * Simple map operator (!) - https://www.w3.org/TR/xpath-31/#id-map-operator * ========================================================================= */ @@ -871,8 +989,9 @@ public R visitSimplemapexpr(SimplemapexprContext ctx) { return handle(ctx, (context) -> handleSimplemapexpr(ctx)); } - /* ======================================================================= - * Arrow operator (=>) - https://www.w3.org/TR/xpath-31/#id-arrow-operator + /* + * ======================================================================= Arrow + * operator (=>) - https://www.w3.org/TR/xpath-31/#id-arrow-operator * ======================================================================= */ diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractCSTVisitorBase.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractCSTVisitorBase.java index 637d24caf..99d4a2009 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractCSTVisitorBase.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractCSTVisitorBase.java @@ -47,6 +47,7 @@ import javax.xml.namespace.QName; import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; public abstract class AbstractCSTVisitorBase extends AbstractAstVisitor { @@ -130,6 +131,28 @@ public IExpression visit(ParseTree tree) { return super.visit(tree); } + @Nullable + protected + R nairyToCollection( + @NonNull CONTEXT context, + int startIndex, + int step, + @NonNull BiFunction parser, + @NonNull Function, R> supplier) { + int numChildren = context.getChildCount(); + + R retval = null; + if (startIndex < numChildren) { + List children = new ArrayList<>((numChildren - startIndex) / step); + for (int idx = startIndex; idx < numChildren; idx += step) { + T result = parser.apply(context, idx); + children.add(result); + } + retval = supplier.apply(children); + } + return retval; + } + /** * Parse the provided context as an n-ary phrase, which will be one of the * following. @@ -272,12 +295,11 @@ protected IExpression handleGroupedNAiry( IExpression retval = null; if (numChildren > 0) { ParseTree leftTree = context.getChild(startingIndex); - IExpression result = ObjectUtils.notNull(leftTree.accept(this)); + retval = ObjectUtils.notNull(leftTree.accept(this)); for (int i = startingIndex + 1; i < numChildren; i = i + step) { - result = parser.apply(context, i, result); + retval = parser.apply(context, i, retval); } - retval = result; } return retval; } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractExpression.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractExpression.java index 967b413c2..b60654f2f 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractExpression.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractExpression.java @@ -28,9 +28,7 @@ import gov.nist.secauto.metaschema.core.metapath.ISequence; import gov.nist.secauto.metaschema.core.metapath.TypeMetapathException; -import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils; 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 edu.umd.cs.findbugs.annotations.NonNull; @@ -54,9 +52,7 @@ public abstract class AbstractExpression implements IExpression { @Nullable public static IAnyAtomicItem getFirstDataItem(@NonNull ISequence sequence, boolean requireSingleton) { - IItem item = FunctionUtils.getFirstItem(sequence, requireSingleton); - - return item == null ? null : FnData.fnDataItem(item); + return FnData.fnData(sequence).getFirstItem(requireSingleton); } @Override diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractExpressionVisitor.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractExpressionVisitor.java index 24e5fe06e..78980013b 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractExpressionVisitor.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractExpressionVisitor.java @@ -37,12 +37,14 @@ import gov.nist.secauto.metaschema.core.metapath.cst.path.Axis; import gov.nist.secauto.metaschema.core.metapath.cst.path.Flag; import gov.nist.secauto.metaschema.core.metapath.cst.path.ModelInstance; +import gov.nist.secauto.metaschema.core.metapath.cst.path.NameTest; import gov.nist.secauto.metaschema.core.metapath.cst.path.RelativeDoubleSlashPath; import gov.nist.secauto.metaschema.core.metapath.cst.path.RelativeSlashPath; import gov.nist.secauto.metaschema.core.metapath.cst.path.RootDoubleSlashPath; import gov.nist.secauto.metaschema.core.metapath.cst.path.RootSlashOnlyPath; import gov.nist.secauto.metaschema.core.metapath.cst.path.RootSlashPath; import gov.nist.secauto.metaschema.core.metapath.cst.path.Step; +import gov.nist.secauto.metaschema.core.metapath.cst.path.Wildcard; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; @@ -56,7 +58,7 @@ * @param * additional state to pass between nodes visited */ -@SuppressWarnings("PMD.CouplingBetweenObjects") +@SuppressWarnings({ "PMD.CouplingBetweenObjects", "PMD.ExcessivePublicCount" }) public abstract class AbstractExpressionVisitor implements IExpressionVisitor { /** @@ -202,7 +204,7 @@ public RESULT visitFlag(Flag expr, CONTEXT context) { } @Override - public RESULT visitFunctionCall(FunctionCall expr, CONTEXT context) { + public RESULT visitFunctionCall(StaticFunctionCall expr, CONTEXT context) { return visitChildren(expr, context); } @@ -242,7 +244,7 @@ public RESULT visitMultiplication(Multiplication expr, CONTEXT context) { } @Override - public RESULT visitName(Name expr, CONTEXT context) { + public RESULT visitName(NameTest expr, CONTEXT context) { return defaultResult(); } @@ -257,7 +259,7 @@ public RESULT visitOr(Or expr, CONTEXT context) { } @Override - public RESULT visitPredicate(Predicate expr, CONTEXT context) { + public RESULT visitPredicate(PredicateExpression expr, CONTEXT context) { return visitChildren(expr, context); } @@ -350,4 +352,39 @@ public RESULT visitFor(For expr, CONTEXT context) { public RESULT visitSimpleMap(SimpleMap expr, CONTEXT context) { return visitChildren(expr, context); } + + @Override + public RESULT visitMapConstructor(MapConstructor expr, CONTEXT context) { + return visitChildren(expr, context); + } + + @Override + public RESULT visitMapConstructorEntry(MapConstructor.Entry expr, CONTEXT context) { + return visitChildren(expr, context); + } + + @Override + public RESULT visitArray(ArraySequenceConstructor expr, CONTEXT context) { + return visitChildren(expr, context); + } + + @Override + public RESULT visitArray(ArraySquareConstructor expr, CONTEXT context) { + return visitChildren(expr, context); + } + + @Override + public RESULT visitPostfixLookup(PostfixLookup expr, CONTEXT context) { + return visitChildren(expr, context); + } + + @Override + public RESULT visitFunctionCallAccessor(FunctionCallAccessor expr, CONTEXT context) { + return visitChildren(expr, context); + } + + @Override + public RESULT visitUnaryLookup(UnaryLookup expr, CONTEXT context) { + return defaultResult(); + } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractFilterExpression.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractFilterExpression.java index 0408ab3ed..5b20b87ff 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractFilterExpression.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractFilterExpression.java @@ -71,7 +71,7 @@ public ISequence accept( ISequence left = getLeft().accept(dynamicContext, focus); ISequence right = getRight().accept(dynamicContext, focus); - List rightList = right.asList(); + List rightList = right.getValue(); return applyFilterTo(left, rightList); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractLookup.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractLookup.java new file mode 100644 index 000000000..5bb77d4b5 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractLookup.java @@ -0,0 +1,231 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.cst; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ICollectionValue; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.InvalidTypeMetapathException; +import gov.nist.secauto.metaschema.core.metapath.function.library.ArrayGet; +import gov.nist.secauto.metaschema.core.metapath.function.library.FnData; +import gov.nist.secauto.metaschema.core.metapath.function.library.MapGet; +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.IIntegerItem; +import gov.nist.secauto.metaschema.core.metapath.item.atomic.IStringItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.ArrayException; +import gov.nist.secauto.metaschema.core.metapath.item.function.IArrayItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.IMapItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.stream.Stream; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public abstract class AbstractLookup implements IExpression { + @NonNull + private final IKeySpecifier keySpecifier; + + protected AbstractLookup(@NonNull IKeySpecifier keySpecifier) { + this.keySpecifier = keySpecifier; + } + + @NonNull + public IKeySpecifier getKeySpecifier() { + return keySpecifier; + } + + protected interface IKeySpecifier { + + default Stream lookup( + @NonNull IItem item, + @NonNull DynamicContext dynamicContext, + @NonNull ISequence focus) { + Stream result; + if (item instanceof IArrayItem) { + result = lookupInArray((IArrayItem) item, dynamicContext, focus); + } else if (item instanceof IMapItem) { + result = lookupInMap((IMapItem) item, dynamicContext, focus); + } else { + throw new InvalidTypeMetapathException(item, + String.format("Item type '%s' is not an array or map.", item.getClass().getName())); + } + return result; + } + + @NonNull + Stream lookupInArray( + @NonNull IArrayItem item, + @NonNull DynamicContext dynamicContext, + @NonNull ISequence focus); + + @NonNull + Stream lookupInMap( + @NonNull IMapItem item, + @NonNull DynamicContext dynamicContext, + @NonNull ISequence focus); + } + + protected static class NCNameKeySpecifier implements IKeySpecifier { + @NonNull + private final String name; + + public NCNameKeySpecifier(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public Stream lookupInArray( + IArrayItem item, + DynamicContext dynamicContext, + ISequence focus) { + throw new InvalidTypeMetapathException(item, + String.format("The key name-based lookup '%s' is not appropriate for an array.", getName())); + } + + @Override + public Stream lookupInMap( + IMapItem item, + DynamicContext dynamicContext, + ISequence focus) { + return ObjectUtils.notNull(Stream.ofNullable(MapGet.get(item, IStringItem.valueOf(name)))); + } + } + + protected static class IntegerLiteralKeySpecifier implements IKeySpecifier { + private final int index; + + public IntegerLiteralKeySpecifier(IIntegerItem literal) { + index = literal.asInteger().intValueExact(); + } + + @Override + public Stream lookupInArray( + IArrayItem item, + DynamicContext dynamicContext, + ISequence focus) { + try { + return ObjectUtils.notNull(Stream.ofNullable(ArrayGet.get(item, index))); + } catch (IndexOutOfBoundsException ex) { + throw new ArrayException( + ArrayException.INDEX_OUT_OF_BOUNDS, + String.format("The index %d is outside the range of values for the array size '%d'.", + index + 1, + item.size()), + ex); + } + } + + @Override + public Stream lookupInMap( + IMapItem item, + DynamicContext dynamicContext, + ISequence focus) { + return ObjectUtils.notNull(Stream.ofNullable(MapGet.get(item, IIntegerItem.valueOf(index)))); + } + } + + protected static class WildcardKeySpecifier implements IKeySpecifier { + + @Override + public Stream lookupInArray( + IArrayItem item, + DynamicContext dynamicContext, + ISequence focus) { + return ObjectUtils.notNull(item.stream()); + } + + @Override + public Stream lookupInMap( + IMapItem item, + DynamicContext dynamicContext, + ISequence focus) { + return ObjectUtils.notNull(item.values().stream()); + } + } + + public static class ParenthesizedExprKeySpecifier implements IKeySpecifier { + @NonNull + private final IExpression keyExpression; + + public ParenthesizedExprKeySpecifier(@NonNull IExpression keyExpression) { + this.keyExpression = keyExpression; + } + + public IExpression getKeyExpression() { + return keyExpression; + } + + @Override + public Stream lookupInArray( + IArrayItem item, + DynamicContext dynamicContext, + ISequence focus) { + ISequence keys = FnData.fnData(getKeyExpression().accept(dynamicContext, focus)); + + return ObjectUtils.notNull(keys.stream() + .flatMap(key -> { + if (key instanceof IIntegerItem) { + int index = ((IIntegerItem) key).asInteger().intValueExact(); + try { + return Stream.ofNullable(ArrayGet.get(item, index)); + } catch (IndexOutOfBoundsException ex) { + throw new ArrayException( + ArrayException.INDEX_OUT_OF_BOUNDS, + String.format("The index %d is outside the range of values for the array size '%d'.", + index + 1, + item.size()), + ex); + } + } + throw new InvalidTypeMetapathException(item, + String.format("The key '%s' of type '%s' is not appropriate for an array lookup.", + key.asString(), + key.getClass().getName())); + + })); + } + + @Override + public Stream lookupInMap( + IMapItem item, + DynamicContext dynamicContext, + ISequence focus) { + ISequence keys + = ObjectUtils.requireNonNull(FnData.fnData(getKeyExpression().accept(dynamicContext, focus))); + + return keys.stream() + .flatMap(key -> { + return Stream.ofNullable(MapGet.get(item, key)); + }); + } + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractNamedInstanceExpression.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractNamedInstanceExpression.java index 69d79049f..1c00129d1 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractNamedInstanceExpression.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/AbstractNamedInstanceExpression.java @@ -27,6 +27,8 @@ package gov.nist.secauto.metaschema.core.metapath.cst; import gov.nist.secauto.metaschema.core.metapath.cst.path.AbstractPathExpression; +import gov.nist.secauto.metaschema.core.metapath.cst.path.NameTest; +import gov.nist.secauto.metaschema.core.metapath.cst.path.Wildcard; import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem; import java.util.List; @@ -50,7 +52,7 @@ public AbstractNamedInstanceExpression(@NonNull IExpression test) { } /** - * Get the {@link Wildcard} or {@link Name} test. + * Get the {@link Wildcard} or {@link NameTest} test. * * @return the test */ diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ArraySequenceConstructor.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ArraySequenceConstructor.java new file mode 100644 index 000000000..6b837b524 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ArraySequenceConstructor.java @@ -0,0 +1,79 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.cst; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.item.function.IArrayItem; + +import java.util.List; + +import edu.umd.cs.findbugs.annotations.Nullable; + +public class ArraySequenceConstructor implements IExpression { + @Nullable + private final IExpression expr; + + public ArraySequenceConstructor(@Nullable IExpression expr) { + this.expr = expr; + } + + @SuppressWarnings("rawtypes") + @Override + public Class getBaseResultType() { + return IArrayItem.class; + } + + @SuppressWarnings("rawtypes") + @Override + public Class getStaticResultType() { + return IArrayItem.class; + } + + @SuppressWarnings("null") + @Override + public List getChildren() { + return List.of(expr); + } + + @Override + public ISequence> accept(DynamicContext dynamicContext, ISequence focus) { + ISequence> retval; + if (expr != null) { + IArrayItem array = IArrayItem.ofCollection(expr.accept(dynamicContext, focus)); + retval = ISequence.of(array); + } else { + retval = ISequence.of(); + } + return retval; + } + + @Override + public RESULT accept(IExpressionVisitor visitor, CONTEXT context) { + return visitor.visitArray(this, context); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Wildcard.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ArraySquareConstructor.java similarity index 71% rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Wildcard.java rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ArraySquareConstructor.java index 087e7cdf5..6a98a508a 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Wildcard.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ArraySquareConstructor.java @@ -28,43 +28,36 @@ import gov.nist.secauto.metaschema.core.metapath.DynamicContext; import gov.nist.secauto.metaschema.core.metapath.ISequence; -import gov.nist.secauto.metaschema.core.metapath.item.ItemUtils; -import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem; +import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.IArrayItem; -import java.util.Collections; import java.util.List; -/** - * The CST node for a Metapath - * wildcard name - * test. - */ -public class Wildcard implements IExpression { - @SuppressWarnings("null") - @Override - public List getChildren() { - return Collections.emptyList(); - } +import edu.umd.cs.findbugs.annotations.NonNull; - @Override - public Class getBaseResultType() { - return INodeItem.class; +public class ArraySquareConstructor implements IExpression { + @NonNull + private final List children; + + public ArraySquareConstructor(@NonNull List children) { + this.children = children; } @Override - public Class getStaticResultType() { - return getBaseResultType(); + public List getChildren() { + return children; } @Override - public RESULT accept(IExpressionVisitor visitor, CONTEXT context) { - return visitor.visitWildcard(this, context); + public ISequence accept(DynamicContext dynamicContext, ISequence focus) { + return ISequence.of(getChildren().stream() + .map(expr -> expr.accept(dynamicContext, focus)) + .map(ISequence::toCollectionValue) + .collect(IArrayItem.toArrayItem())); } @Override - public ISequence accept( - DynamicContext dynamicContext, ISequence focus) { - return ISequence.of(focus.asStream() - .map(item -> ItemUtils.checkItemIsNodeItemForStep(item))); + public RESULT accept(IExpressionVisitor visitor, CONTEXT context) { + return visitor.visitArray(this, context); } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/BuildCSTVisitor.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/BuildCSTVisitor.java index 157a3875a..e22bbd382 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/BuildCSTVisitor.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/BuildCSTVisitor.java @@ -26,6 +26,8 @@ package gov.nist.secauto.metaschema.core.metapath.cst; +import gov.nist.secauto.metaschema.core.metapath.EQNameUtils; +import gov.nist.secauto.metaschema.core.metapath.StaticContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.AbbrevforwardstepContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.AbbrevreversestepContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.AdditiveexprContext; @@ -36,6 +38,7 @@ import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.AxisstepContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ComparisonexprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ContextitemexprContext; +import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.CurlyarrayconstructorContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.EqnameContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ExprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ExprsingleContext; @@ -45,9 +48,15 @@ import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.GeneralcompContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.IfexprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.IntersectexceptexprContext; +import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.KeyspecifierContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.LetexprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.LiteralContext; +import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.LookupContext; +import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.MapconstructorContext; +import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.MapconstructorentryContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.MultiplicativeexprContext; +import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.NametestContext; +import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.NodetestContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.NumericliteralContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.OrexprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ParenthesizedexprContext; @@ -63,14 +72,17 @@ import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.SimpleletbindingContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.SimpleletclauseContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.SimplemapexprContext; +import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.SquarearrayconstructorContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.StringconcatexprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.UnaryexprContext; +import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.UnarylookupContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.UnionexprContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.ValuecompContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.VarnameContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.VarrefContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10.WildcardContext; import gov.nist.secauto.metaschema.core.metapath.antlr.Metapath10Lexer; +import gov.nist.secauto.metaschema.core.metapath.cst.AbstractLookup.IKeySpecifier; import gov.nist.secauto.metaschema.core.metapath.cst.comparison.GeneralComparison; import gov.nist.secauto.metaschema.core.metapath.cst.comparison.ValueComparison; import gov.nist.secauto.metaschema.core.metapath.cst.math.Addition; @@ -81,14 +93,20 @@ import gov.nist.secauto.metaschema.core.metapath.cst.math.Subtraction; import gov.nist.secauto.metaschema.core.metapath.cst.path.Axis; import gov.nist.secauto.metaschema.core.metapath.cst.path.Flag; +import gov.nist.secauto.metaschema.core.metapath.cst.path.INameTestExpression; +import gov.nist.secauto.metaschema.core.metapath.cst.path.INodeTestExpression; import gov.nist.secauto.metaschema.core.metapath.cst.path.ModelInstance; +import gov.nist.secauto.metaschema.core.metapath.cst.path.NameTest; import gov.nist.secauto.metaschema.core.metapath.cst.path.RelativeDoubleSlashPath; import gov.nist.secauto.metaschema.core.metapath.cst.path.RelativeSlashPath; import gov.nist.secauto.metaschema.core.metapath.cst.path.RootDoubleSlashPath; import gov.nist.secauto.metaschema.core.metapath.cst.path.RootSlashOnlyPath; import gov.nist.secauto.metaschema.core.metapath.cst.path.RootSlashPath; import gov.nist.secauto.metaschema.core.metapath.cst.path.Step; +import gov.nist.secauto.metaschema.core.metapath.cst.path.Wildcard; import gov.nist.secauto.metaschema.core.metapath.function.ComparisonFunctions; +import gov.nist.secauto.metaschema.core.metapath.item.atomic.IIntegerItem; +import gov.nist.secauto.metaschema.core.metapath.item.node.IDefinitionNodeItem; import gov.nist.secauto.metaschema.core.util.CollectionUtil; import gov.nist.secauto.metaschema.core.util.ObjectUtils; @@ -103,9 +121,12 @@ import java.util.List; import java.util.ListIterator; import java.util.Map; +import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; +import javax.xml.namespace.QName; + import edu.umd.cs.findbugs.annotations.NonNull; /** @@ -119,11 +140,21 @@ }) public class BuildCSTVisitor extends AbstractCSTVisitorBase { + @NonNull + private final StaticContext context; - /* ============================================================ - * Expressions - https://www.w3.org/TR/xpath-31/#id-expressions - * ============================================================ - */ + public BuildCSTVisitor(@NonNull StaticContext context) { + this.context = context; + } + + // ============================================================ + // Expressions - https://www.w3.org/TR/xpath-31/#id-expressions + // ============================================================ + + @NonNull + protected StaticContext getContext() { + return context; + } @Override protected IExpression handleExpr(ExprContext ctx) { @@ -133,10 +164,9 @@ protected IExpression handleExpr(ExprContext ctx) { }); } - /* ================================================================= - * Literal Expressions - https://www.w3.org/TR/xpath-31/#id-literals - * ================================================================= - */ + // ================================================================= + // Literal Expressions - https://www.w3.org/TR/xpath-31/#id-literals + // ================================================================= @Override protected IExpression handleStringLiteral(LiteralContext ctx) { @@ -163,42 +193,251 @@ protected IExpression handleNumericLiteral(NumericliteralContext ctx) { return retval; } - /* ================================================================== - * Variable References - https://www.w3.org/TR/xpath-31/#id-variables - * ================================================================== - */ + // ================================================================== + // Variable References - https://www.w3.org/TR/xpath-31/#id-variables + // ================================================================== @Override protected IExpression handleVarref(VarrefContext ctx) { - Name varName = (Name) ctx.varname().accept(this); - assert varName != null; - return new VariableReference(varName); + return new VariableReference( + EQNameUtils.parseName( + ctx.varname().eqname().getText(), + getContext().getVariablePrefixResolver())); } - /* ================================================================================= - * Parenthesized Expressions - https://www.w3.org/TR/xpath-31/#id-paren-expressions - * ================================================================================= - */ + // ==================================================================== + // For Expressions - https://www.w3.org/TR/xpath-31/#id-for-expressions + // ==================================================================== + + @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") + @Override + protected IExpression handleForexpr(ForexprContext ctx) { + SimpleforclauseContext simpleForClause = ctx.simpleforclause(); + + // for SimpleForBinding ("," SimpleForBinding)* + int bindingCount = simpleForClause.getChildCount() / 2; + + @NonNull IExpression retval = ObjectUtils.notNull(ctx.exprsingle().accept(this)); + + // step through in reverse + for (int idx = bindingCount - 1; idx >= 0; idx--) { + SimpleforbindingContext simpleForBinding = simpleForClause.simpleforbinding(idx); + + VarnameContext varName = simpleForBinding.varname(); + ExprsingleContext exprSingle = simpleForBinding.exprsingle(); + + IExpression boundExpression = exprSingle.accept(this); + assert boundExpression != null; + + QName qname = EQNameUtils.parseName( + varName.eqname().getText(), + getContext().getVariablePrefixResolver()); + + Let.VariableDeclaration variable = new Let.VariableDeclaration(qname, boundExpression); + + retval = new For(variable, retval); + } + return retval; + } + + // ==================================================================== + // Let Expressions - https://www.w3.org/TR/xpath-31/#id-let-expressions + // ==================================================================== + + @Override + protected IExpression handleLet(LetexprContext context) { + @NonNull IExpression retval = ObjectUtils.notNull(context.exprsingle().accept(this)); + + SimpleletclauseContext letClause = context.simpleletclause(); + List clauses = letClause.simpleletbinding(); + + ListIterator reverseListIterator = clauses.listIterator(clauses.size()); + while (reverseListIterator.hasPrevious()) { + SimpleletbindingContext simpleCtx = reverseListIterator.previous(); + + IExpression boundExpression = simpleCtx.exprsingle().accept(this); + assert boundExpression != null; + + QName varName = EQNameUtils.parseName( + simpleCtx.varname().eqname().getText(), + getContext().getVariablePrefixResolver()); + + retval = new Let(varName, boundExpression, retval); // NOPMD intended + } + return retval; + } + + // ====================================================================== + // Map Constructors - https://www.w3.org/TR/xpath-31/#id-map-constructors + // ====================================================================== + + @Override + protected MapConstructor handleMapConstructor(MapconstructorContext context) { + return context.getChildCount() == 3 + // empty + ? new MapConstructor(CollectionUtil.emptyList()) + // with members + : nairyToCollection(context, 3, 2, + (ctx, idx) -> { + int pos = (idx - 3) / 2; + MapconstructorentryContext entry = ctx.mapconstructorentry(pos); + assert entry != null; + return new MapConstructor.Entry(entry.mapkeyexpr().accept(this), entry.mapvalueexpr().accept(this)); + }, + children -> { + assert children != null; + return new MapConstructor(children); + }); + } + + // ============================================================== + // Array Constructors - https://www.w3.org/TR/xpath-31/#id-arrays + // ============================================================== + + @Override + protected IExpression handleArrayConstructor(SquarearrayconstructorContext context) { + return context.getChildCount() == 2 + // empty + ? new ArraySquareConstructor(CollectionUtil.emptyList()) + // with members + : nairyToCollection(context, 1, 2, + (ctx, idx) -> { + int pos = (idx - 1) / 2; + ParseTree tree = ctx.exprsingle(pos); + return visit(tree); + }, + children -> { + assert children != null; + return new ArraySquareConstructor(children); + }); + } + + @Override + protected IExpression handleArrayConstructor(CurlyarrayconstructorContext ctx) { + return new ArraySequenceConstructor(visit(ctx.enclosedexpr())); + } + + // =============================================== + // Unary Lookup - + // https://www.w3.org/TR/xpath-31/#id-unary-lookup + // =============================================== + + @Override + protected IExpression handleUnarylookup(UnarylookupContext ctx) { + KeyspecifierContext specifier = ctx.keyspecifier(); + + IKeySpecifier keySpecifier; + if (specifier.parenthesizedexpr() != null) { + keySpecifier + = new UnaryLookup.ParenthesizedExprKeySpecifier( + ObjectUtils.requireNonNull(specifier.parenthesizedexpr().accept(this))); + } else if (specifier.NCName() != null) { + keySpecifier + = new UnaryLookup.NCNameKeySpecifier(ObjectUtils.requireNonNull(specifier.NCName().getText())); + } else if (specifier.IntegerLiteral() != null) { + keySpecifier = new UnaryLookup.IntegerLiteralKeySpecifier( + IIntegerItem.valueOf(ObjectUtils.requireNonNull(specifier.IntegerLiteral().getText()))); + } else if (specifier.STAR() != null) { + keySpecifier = new UnaryLookup.WildcardKeySpecifier(); + } else { + throw new UnsupportedOperationException("unknown key specifier"); + } + return new UnaryLookup(keySpecifier); + } + + // ========================================================= + // Quantified Expressions - + // https://www.w3.org/TR/xpath-31/#id-quantified-expressions + // ========================================================= + + @Override + protected IExpression handleQuantifiedexpr(QuantifiedexprContext ctx) { + Quantified.Quantifier quantifier; + int type = ((TerminalNode) ctx.getChild(0)).getSymbol().getType(); + switch (type) { + case Metapath10Lexer.KW_SOME: + quantifier = Quantified.Quantifier.SOME; + break; + case Metapath10Lexer.KW_EVERY: + quantifier = Quantified.Quantifier.EVERY; + break; + default: + throw new UnsupportedOperationException(((TerminalNode) ctx.getChild(0)).getSymbol().getText()); + } + + int numVars = (ctx.getChildCount() - 2) / 5; // children - "satisfies expr" / ", $ varName in expr" + Map vars = new LinkedHashMap<>(); // NOPMD ordering needed + int offset = 0; + for (; offset < numVars; offset++) { + // $ + QName varName = EQNameUtils.parseName( + ctx.varname(offset).eqname().getText(), + getContext().getVariablePrefixResolver()); + + // in + IExpression varExpr = visit(ctx.exprsingle(offset)); + + vars.put(varName, varExpr); + } + + IExpression satisfies = visit(ctx.exprsingle(offset)); + + return new Quantified(quantifier, vars, satisfies); + } + + // ======================================================================= + // Arrow operator (=>) - https://www.w3.org/TR/xpath-31/#id-arrow-operator + // ======================================================================= + + @Override + protected IExpression handleArrowexpr(ArrowexprContext context) { + // TODO: handle additional syntax for varef and parenthesized + return handleGroupedNAiry(context, 0, 3, (ctx, idx, left) -> { + // the next child is "=>" + assert "=>".equals(ctx.getChild(idx).getText()); + + int offset = (idx - 1) / 3; + + ArrowfunctionspecifierContext fcCtx = ctx.getChild(ArrowfunctionspecifierContext.class, offset); + ArgumentlistContext argumentCtx = ctx.getChild(ArgumentlistContext.class, offset); + + QName name = EQNameUtils.parseName( + fcCtx.eqname().getText(), + getContext().getFunctionPrefixResolver()); + + try (Stream args = Stream.concat( + Stream.of(left), + parseArgumentList(ObjectUtils.notNull(argumentCtx)))) { + assert args != null; + + return new StaticFunctionCall(name, ObjectUtils.notNull(args.collect(Collectors.toUnmodifiableList()))); + } + }); + } + + // ==================================================== + // Parenthesized Expressions - + // https://www.w3.org/TR/xpath-31/#id-paren-expressions + // ==================================================== @Override protected IExpression handleEmptyParenthesizedexpr(ParenthesizedexprContext ctx) { return EmptySequence.instance(); } - /* ===================================================================================== - * Context Item Expression - https://www.w3.org/TR/xpath-31/#id-context-item-expression - * ===================================================================================== - */ + // ========================================================== + // Context Item Expression - + // https://www.w3.org/TR/xpath-31/#id-context-item-expression + // ========================================================== @Override protected IExpression handleContextitemexpr(ContextitemexprContext ctx) { return ContextItem.instance(); } - /* ========================================================================= - * Static Function Calls - https://www.w3.org/TR/xpath-31/#id-function-calls - * ========================================================================= - */ + // ========================================================================= + // Static Function Calls - https://www.w3.org/TR/xpath-31/#id-function-calls + // ========================================================================= /** * Parse a list of arguments. @@ -229,21 +468,18 @@ protected Stream parseArgumentList(@NonNull ArgumentlistContext con @Override protected IExpression handleFunctioncall(FunctioncallContext ctx) { - EqnameContext nameCtx = ctx.eqname(); - String name = nameCtx.getText(); - - assert name != null; - - return new FunctionCall( - name, + QName qname = EQNameUtils.parseName( + ctx.eqname().getText(), + getContext().getFunctionPrefixResolver()); + return new StaticFunctionCall( + qname, ObjectUtils.notNull(parseArgumentList(ObjectUtils.notNull(ctx.argumentlist())) .collect(Collectors.toUnmodifiableList()))); } - /* ========================================================================= - * Filter Expressions - https://www.w3.org/TR/xpath-31/#id-filter-expression - * ========================================================================= - */ + // ========================================================================= + // Filter Expressions - https://www.w3.org/TR/xpath-31/#id-filter-expression + // ========================================================================= /** * Parse a predicate AST. @@ -293,22 +529,65 @@ protected List parsePredicates(@NonNull ParseTree context, int star } @Override - protected IExpression handlePostfixexpr(PostfixexprContext ctx) { - int numChildren = ctx.getChildCount(); - ParseTree primaryTree = ctx.getChild(0); - IExpression retval = ObjectUtils.notNull(primaryTree.accept(this)); + protected IExpression handlePostfixexpr(PostfixexprContext context) { + return handleGroupedNAiry( + context, + 0, + 1, + (ctx, idx, left) -> { + ParseTree tree = ctx.getChild(idx); + IExpression result; + if (tree instanceof ArgumentlistContext) { + // map or array access using function call syntax + result = new FunctionCallAccessor( + left, + parseArgumentList((ArgumentlistContext) tree).findFirst().get()); + } else if (tree instanceof PredicateContext) { + result = new PredicateExpression( + left, + CollectionUtil.singletonList(parsePredicate((PredicateContext) tree))); + } else if (tree instanceof LookupContext) { + KeyspecifierContext specifier = ((LookupContext) tree).keyspecifier(); + + IKeySpecifier keySpecifier; + if (specifier.parenthesizedexpr() != null) { + keySpecifier + = new PostfixLookup.ParenthesizedExprKeySpecifier( + ObjectUtils.requireNonNull(specifier.parenthesizedexpr().accept(this))); + } else if (specifier.NCName() != null) { + keySpecifier + = new PostfixLookup.NCNameKeySpecifier(ObjectUtils.requireNonNull(specifier.NCName().getText())); + } else if (specifier.IntegerLiteral() != null) { + keySpecifier = new PostfixLookup.IntegerLiteralKeySpecifier( + IIntegerItem.valueOf(ObjectUtils.requireNonNull(specifier.IntegerLiteral().getText()))); + } else if (specifier.STAR() != null) { + keySpecifier = new PostfixLookup.WildcardKeySpecifier(); + } else { + throw new UnsupportedOperationException("unknown key specifier"); + } + result = new PostfixLookup(left, keySpecifier); + } else { + result = visit(tree); + } + return result; + }); + } - List predicates = numChildren > 1 ? parsePredicates(ctx, 1) : CollectionUtil.emptyList(); + // ====================================================================== + // Path Expressions - https://www.w3.org/TR/xpath-31/#id-path-expressions + // ====================================================================== - if (!predicates.isEmpty()) { - retval = new Predicate(retval, predicates); - } - return retval; + @Override + protected IExpression handlePredicate(PredicateContext ctx) { + parsePredicate(ctx); + return null; + } + + @Override + protected IExpression handleLookup(LookupContext ctx) { + // TODO Auto-generated method stub + return null; } - /* ====================================================================== - * Path Expressions - https://www.w3.org/TR/xpath-31/#id-path-expressions - * ====================================================================== - */ @Override protected IExpression handlePathexpr(PathexprContext ctx) { @@ -342,10 +621,10 @@ protected IExpression handlePathexpr(PathexprContext ctx) { return retval; } - /* ======================================================================================= - * RelativePath Expressions - https://www.w3.org/TR/xpath-31/#id-relative-path-expressions - * ======================================================================================= - */ + // ============================================================ + // RelativePath Expressions - + // https://www.w3.org/TR/xpath-31/#id-relative-path-expressions + // ============================================================ @Override protected IExpression handleRelativepathexpr(RelativepathexprContext context) { @@ -372,35 +651,46 @@ protected IExpression handleRelativepathexpr(RelativepathexprContext context) { }); } - /* ================================================ - * Steps - https://www.w3.org/TR/xpath-31/#id-steps - * ================================================ - */ + // ================================================ + // Steps - https://www.w3.org/TR/xpath-31/#id-steps + // ================================================ @Override protected IExpression handleForwardstep(ForwardstepContext ctx) { - assert ctx.getChildCount() == 2; + AbbrevforwardstepContext abbrev = ctx.abbrevforwardstep(); - Token token = (Token) ctx.forwardaxis().getChild(0).getPayload(); + Step retval; + if (abbrev == null) { + assert ctx.getChildCount() == 2; - Axis axis; - switch (token.getType()) { - case Metapath10Lexer.KW_SELF: - axis = Axis.SELF; - break; - case Metapath10Lexer.KW_CHILD: - axis = Axis.CHILDREN; - break; - case Metapath10Lexer.KW_DESCENDANT: - axis = Axis.DESCENDANT; - break; - case Metapath10Lexer.KW_DESCENDANT_OR_SELF: - axis = Axis.DESCENDANT_OR_SELF; - break; - default: - throw new UnsupportedOperationException(token.getText()); + Token token = (Token) ctx.forwardaxis().getChild(0).getPayload(); + + Axis axis; + switch (token.getType()) { + case Metapath10Lexer.KW_SELF: + axis = Axis.SELF; + break; + case Metapath10Lexer.KW_CHILD: + axis = Axis.CHILDREN; + break; + case Metapath10Lexer.KW_DESCENDANT: + axis = Axis.DESCENDANT; + break; + case Metapath10Lexer.KW_DESCENDANT_OR_SELF: + axis = Axis.DESCENDANT_OR_SELF; + break; + default: + throw new UnsupportedOperationException(token.getText()); + } + retval = new Step(axis, parseNodeTest(ctx.nodetest(), false)); + } else { + retval = new Step( + Axis.CHILDREN, + parseNodeTest( + ctx.nodetest(), + abbrev.AT() != null)); } - return new Step(axis, visit(ctx.nametest())); + return retval; } @Override @@ -423,49 +713,77 @@ protected IExpression handleReversestep(ReversestepContext ctx) { default: throw new UnsupportedOperationException(token.getText()); } - return new Step(axis, visit(ctx.nametest())); + return new Step(axis, parseNodeTest(ctx.nodetest(), false)); } - /* ====================================================================== - * Predicates within Steps - https://www.w3.org/TR/xpath-31/#id-predicate - * ====================================================================== - */ - - @Override - protected IExpression handleAxisstep(AxisstepContext ctx) { - IExpression step = visit(ctx.getChild(0)); - ParseTree predicateTree = ctx.getChild(1); - assert predicateTree != null; + // ======================================================= + // Node Tests - https://www.w3.org/TR/xpath-31/#node-tests + // ======================================================= - List predicates = parsePredicates(predicateTree, 0); - - return predicates.isEmpty() ? step : new Predicate(step, predicates); + protected INodeTestExpression parseNodeTest(NodetestContext ctx, boolean flag) { + // TODO: implement kind test + NametestContext nameTestCtx = ctx.nametest(); + return parseNameTest(nameTestCtx, flag); } - /* ======================================================= - * Node Tests - https://www.w3.org/TR/xpath-31/#node-tests - * ======================================================= - */ + protected INameTestExpression parseNameTest(NametestContext ctx, boolean flag) { + ParseTree testType = ObjectUtils.requireNonNull(ctx.getChild(0)); + INameTestExpression retval; + if (testType instanceof EqnameContext) { + QName qname = EQNameUtils.parseName( + ctx.eqname().getText(), + flag ? getContext().getFlagPrefixResolver() : getContext().getModelPrefixResolver()); + retval = new NameTest(qname); + } else { // wildcard + retval = handleWildcard((WildcardContext) testType); + } + return retval; + } @Override - protected IExpression handleEqname(EqnameContext ctx) { - ParseTree tree = ctx.getChild(0); - String name = ((TerminalNode) tree).getText(); - - assert name != null; + protected Wildcard handleWildcard(WildcardContext ctx) { + Predicate> matcher = null; + if (ctx.STAR() == null) { + if (ctx.CS() != null) { + // specified prefix, any local-name + String prefix = ctx.NCName().getText(); + String namespace = getContext().lookupNamespaceForPrefix(prefix); + if (namespace == null) { + throw new IllegalStateException(String.format("Prefix '%s' did not map to a namespace.", prefix)); + } + matcher = new Wildcard.MatchAnyLocalName(namespace); + } else if (ctx.SC() != null) { + // any prefix, specified local-name + matcher = new Wildcard.MatchAnyNamespace(ctx.NCName().getText()); + } else { + // specified braced namespace, any local-name + String bracedUriLiteral = ctx.BracedURILiteral().getText(); + String namespace = bracedUriLiteral.substring(2, bracedUriLiteral.length() - 1); + matcher = new Wildcard.MatchAnyLocalName(namespace); + } + } // star needs no matcher: any prefix, any local-name - return new Name(name); + return new Wildcard(matcher); } + // ====================================================================== + // Predicates within Steps - https://www.w3.org/TR/xpath-31/#id-predicate + // ====================================================================== + @Override - protected IExpression handleWildcard(WildcardContext ctx) { - return new Wildcard(); + protected IExpression handleAxisstep(AxisstepContext ctx) { + IExpression step = visit(ctx.getChild(0)); + ParseTree predicateTree = ctx.getChild(1); + assert predicateTree != null; + + List predicates = parsePredicates(predicateTree, 0); + + return predicates.isEmpty() ? step : new PredicateExpression(step, predicates); } - /* =========================================================== - * Abbreviated Syntax - https://www.w3.org/TR/xpath-31/#abbrev - * =========================================================== - */ + // =========================================================== + // Abbreviated Syntax - https://www.w3.org/TR/xpath-31/#abbrev + // =========================================================== @Override protected IExpression handleAbbrevforwardstep(AbbrevforwardstepContext ctx) { @@ -473,10 +791,10 @@ protected IExpression handleAbbrevforwardstep(AbbrevforwardstepContext ctx) { IExpression retval; if (numChildren == 1) { - retval = new ModelInstance(visit(ctx.getChild(0))); + retval = new ModelInstance(parseNodeTest(ctx.nodetest(), false)); } else { // this is an AT test - retval = new Flag(visit(ctx.getChild(1))); + retval = new Flag(parseNodeTest(ctx.nodetest(), true)); } return retval; } @@ -486,10 +804,9 @@ protected IExpression handleAbbrevreversestep(AbbrevreversestepContext ctx) { return Axis.PARENT; } - /* ====================================================================== - * Constructing Sequences - https://www.w3.org/TR/xpath-31/#construct_seq - * ====================================================================== - */ + // ====================================================================== + // Constructing Sequences - https://www.w3.org/TR/xpath-31/#construct_seq + // ====================================================================== @Override protected IExpression handleRangeexpr(RangeexprContext ctx) { @@ -501,10 +818,9 @@ protected IExpression handleRangeexpr(RangeexprContext ctx) { return new Range(left, right); } - /* ======================================================================== - * Combining Node Sequences - https://www.w3.org/TR/xpath-31/#combining_seq - * ======================================================================== - */ + // ======================================================================== + // Combining Node Sequences - https://www.w3.org/TR/xpath-31/#combining_seq + // ======================================================================== @Override protected IExpression handleUnionexpr(UnionexprContext ctx) { @@ -539,10 +855,9 @@ protected IExpression handleIntersectexceptexpr(IntersectexceptexprContext conte }); } - /* ====================================================================== - * Arithmetic Expressions - https://www.w3.org/TR/xpath-31/#id-arithmetic - * ====================================================================== - */ + // ====================================================================== + // Arithmetic Expressions - https://www.w3.org/TR/xpath-31/#id-arithmetic + // ====================================================================== @Override protected IExpression handleAdditiveexpr(AdditiveexprContext context) { @@ -630,10 +945,10 @@ protected IExpression handleUnaryexpr(UnaryexprContext ctx) { return retval; } - /* ======================================================================================== - * String Concatenation Expressions - https://www.w3.org/TR/xpath-31/#id-string-concat-expr - * ======================================================================================== - */ + // ===================================================== + // String Concatenation Expressions - + // https://www.w3.org/TR/xpath-31/#id-string-concat-expr + // ===================================================== @Override protected IExpression handleStringconcatexpr(StringconcatexprContext ctx) { @@ -643,10 +958,9 @@ protected IExpression handleStringconcatexpr(StringconcatexprContext ctx) { }); } - /* ======================================================================= - * Comparison Expressions - https://www.w3.org/TR/xpath-31/#id-comparisons - * ======================================================================= - */ + // ======================================================================= + // Comparison Expressions - https://www.w3.org/TR/xpath-31/#id-comparisons + // ======================================================================= @Override protected IExpression handleComparisonexpr(ComparisonexprContext ctx) { // NOPMD - ok @@ -719,10 +1033,9 @@ protected IExpression handleComparisonexpr(ComparisonexprContext ctx) { // NOPMD return retval; } - /* ============================================================================ - * Logical Expressions - https://www.w3.org/TR/xpath-31/#id-logical-expressions - * ============================================================================ - */ + // ============================================================================ + // Logical Expressions - https://www.w3.org/TR/xpath-31/#id-logical-expressions + // ============================================================================ @Override protected IExpression handleOrexpr(OrexprContext ctx) { @@ -740,72 +1053,9 @@ protected IExpression handleAndexpr(AndexprContext ctx) { }); } - /* ==================================================================== - * For Expressions - https://www.w3.org/TR/xpath-31/#id-for-expressions - * ==================================================================== - */ - - @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") - @Override - protected IExpression handleForexpr(ForexprContext ctx) { - SimpleforclauseContext simpleForClause = ctx.simpleforclause(); - - // for SimpleForBinding ("," SimpleForBinding)* - int bindingCount = simpleForClause.getChildCount() / 2; - - @NonNull IExpression retval = ObjectUtils.notNull(ctx.exprsingle().accept(this)); - - // step through in reverse - for (int idx = bindingCount - 1; idx >= 0; idx--) { - SimpleforbindingContext simpleForBinding = simpleForClause.simpleforbinding(idx); - - VarnameContext varName = simpleForBinding.varname(); - ExprsingleContext exprSingle = simpleForBinding.exprsingle(); - - Name name = (Name) varName.accept(this); - IExpression boundExpression = exprSingle.accept(this); - - assert name != null; - assert boundExpression != null; - - Let.VariableDeclaration variable = new Let.VariableDeclaration(name, boundExpression); - - retval = new For(variable, retval); - } - return retval; - } - - /* ==================================================================== - * Let Expressions - https://www.w3.org/TR/xpath-31/#id-let-expressions - * ==================================================================== - */ - - @Override - protected IExpression handleLet(LetexprContext context) { - @NonNull IExpression retval = ObjectUtils.notNull(context.exprsingle().accept(this)); - - SimpleletclauseContext letClause = context.simpleletclause(); - List clauses = letClause.simpleletbinding(); - - ListIterator reverseListIterator = clauses.listIterator(clauses.size()); - while (reverseListIterator.hasPrevious()) { - SimpleletbindingContext simpleCtx = reverseListIterator.previous(); - - Name varName = (Name) simpleCtx.varname().accept(this); - IExpression boundExpression = simpleCtx.exprsingle().accept(this); - - assert varName != null; - assert boundExpression != null; - - retval = new Let(varName, boundExpression, retval); // NOPMD intended - } - return retval; - } - - /* ========================================================================= - * Conditional Expressions - https://www.w3.org/TR/xpath-31/#id-conditionals - * ========================================================================= - */ + // ========================================================================= + // Conditional Expressions - https://www.w3.org/TR/xpath-31/#id-conditionals + // ========================================================================= @Override protected IExpression handleIfexpr(IfexprContext ctx) { @@ -816,47 +1066,9 @@ protected IExpression handleIfexpr(IfexprContext ctx) { return new If(testExpr, thenExpr, elseExpr); } - /* ================================================================================== - * Quantified Expressions - https://www.w3.org/TR/xpath-31/#id-quantified-expressions - * ================================================================================== - */ - - @Override - protected IExpression handleQuantifiedexpr(QuantifiedexprContext ctx) { - Quantified.Quantifier quantifier; - int type = ((TerminalNode) ctx.getChild(0)).getSymbol().getType(); - switch (type) { - case Metapath10Lexer.KW_SOME: - quantifier = Quantified.Quantifier.SOME; - break; - case Metapath10Lexer.KW_EVERY: - quantifier = Quantified.Quantifier.EVERY; - break; - default: - throw new UnsupportedOperationException(((TerminalNode) ctx.getChild(0)).getSymbol().getText()); - } - - int numVars = (ctx.getChildCount() - 2) / 5; // children - "satisfies expr" / ", $ varName in expr" - Map vars = new LinkedHashMap<>(); // NOPMD ordering needed - int offset = 0; - for (; offset < numVars; offset++) { - // $ - String varName = ((Name) visit(ctx.varname(offset))).getValue(); - // in - IExpression varExpr = visit(ctx.exprsingle(offset)); - - vars.put(varName, varExpr); - } - - IExpression satisfies = visit(ctx.exprsingle(offset)); - - return new Quantified(quantifier, vars, satisfies); - } - - /* ========================================================================= - * Simple map operator (!) - https://www.w3.org/TR/xpath-31/#id-map-operator - * ========================================================================= - */ + // ========================================================================= + // Simple map operator (!) - https://www.w3.org/TR/xpath-31/#id-map-operator + // ========================================================================= @Override protected IExpression handleSimplemapexpr(SimplemapexprContext context) { @@ -868,34 +1080,4 @@ protected IExpression handleSimplemapexpr(SimplemapexprContext context) { return new SimpleMap(left, right); }); } - - /* ======================================================================= - * Arrow operator (=>) - https://www.w3.org/TR/xpath-31/#id-arrow-operator - * ======================================================================= - */ - - @Override - protected IExpression handleArrowexpr(ArrowexprContext context) { - // TODO: handle additional syntax for varef and parenthesized - return handleGroupedNAiry(context, 0, 3, (ctx, idx, left) -> { - // the next child is "=>" - assert "=>".equals(ctx.getChild(idx).getText()); - - int offset = (idx - 1) / 3; - - ArrowfunctionspecifierContext fcCtx = ctx.getChild(ArrowfunctionspecifierContext.class, offset); - ArgumentlistContext argumentCtx = ctx.getChild(ArgumentlistContext.class, offset); - // QName name = toQName( - String name = fcCtx.eqname().getText(); - assert name != null; - - try (Stream args = Stream.concat( - Stream.of(left), - parseArgumentList(ObjectUtils.notNull(argumentCtx)))) { - assert args != null; - - return new FunctionCall(name, ObjectUtils.notNull(args.collect(Collectors.toUnmodifiableList()))); - } - }); - } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/CSTPrinter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/CSTPrinter.java index c5be781ad..5e3914b10 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/CSTPrinter.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/CSTPrinter.java @@ -37,12 +37,14 @@ import gov.nist.secauto.metaschema.core.metapath.cst.path.Axis; import gov.nist.secauto.metaschema.core.metapath.cst.path.Flag; import gov.nist.secauto.metaschema.core.metapath.cst.path.ModelInstance; +import gov.nist.secauto.metaschema.core.metapath.cst.path.NameTest; import gov.nist.secauto.metaschema.core.metapath.cst.path.RelativeDoubleSlashPath; import gov.nist.secauto.metaschema.core.metapath.cst.path.RelativeSlashPath; import gov.nist.secauto.metaschema.core.metapath.cst.path.RootDoubleSlashPath; import gov.nist.secauto.metaschema.core.metapath.cst.path.RootSlashOnlyPath; import gov.nist.secauto.metaschema.core.metapath.cst.path.RootSlashPath; import gov.nist.secauto.metaschema.core.metapath.cst.path.Step; +import gov.nist.secauto.metaschema.core.metapath.cst.path.Wildcard; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; @@ -64,6 +66,7 @@ public static String toString(@NonNull IExpression expr) { return new CSTPrinterVisitor().visit(expr); } + @SuppressWarnings("PMD.ExcessivePublicCount") private static final class CSTPrinterVisitor extends AbstractExpressionVisitor { @@ -180,7 +183,7 @@ public String visitFlag(Flag expr, State context) { } @Override - public String visitFunctionCall(FunctionCall expr, State context) { + public String visitFunctionCall(StaticFunctionCall expr, State context) { return appendNode(expr, super.visitFunctionCall(expr, context), context); } @@ -220,7 +223,7 @@ public String visitMultiplication(Multiplication expr, State context) { } @Override - public String visitName(Name expr, State context) { + public String visitName(NameTest expr, State context) { return appendNode(expr, super.visitName(expr, context), context); } @@ -240,7 +243,7 @@ public String visitAxis(Axis expr, State context) { } @Override - public String visitPredicate(Predicate expr, State context) { + public String visitPredicate(PredicateExpression expr, State context) { return appendNode(expr, super.visitPredicate(expr, context), context); } @@ -334,6 +337,40 @@ public String visitSimpleMap(SimpleMap expr, State context) { return appendNode(expr, super.visitSimpleMap(expr, context), context); } + @Override + public String visitArray(ArraySequenceConstructor expr, State context) { + return appendNode(expr, super.visitArray(expr, context), context); + } + + @Override + public String visitArray(ArraySquareConstructor expr, State context) { + return appendNode(expr, super.visitArray(expr, context), context); + } + + @Override + public String visitPostfixLookup(PostfixLookup expr, State context) { + return appendNode(expr, super.visitPostfixLookup(expr, context), context); + } + + @Override + public String visitFunctionCallAccessor(FunctionCallAccessor expr, State context) { + return appendNode(expr, super.visitFunctionCallAccessor(expr, context), context); + } + + @Override + public String visitUnaryLookup(UnaryLookup expr, State context) { + return appendNode(expr, super.visitUnaryLookup(expr, context), context); + } + + @Override + public String visitMapConstructor(MapConstructor expr, State context) { + return appendNode(expr, super.visitMapConstructor(expr, context), context); + } + + @Override + public String visitMapConstructorEntry(MapConstructor.Entry expr, State context) { + return appendNode(expr, super.visitMapConstructorEntry(expr, context), context); + } } static class State { diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Except.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Except.java index cacef3b31..8070ad825 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Except.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Except.java @@ -55,7 +55,7 @@ public Except(@NonNull IExpression left, @NonNull IExpression right) { @Override protected ISequence applyFilterTo(@NonNull ISequence result, @NonNull List items) { - return ISequence.of(result.asStream() + return ISequence.of(result.stream() .filter(item -> !items.contains(item))); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ExpressionUtils.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ExpressionUtils.java index 5fc6ec69f..d900ed4ae 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ExpressionUtils.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ExpressionUtils.java @@ -61,7 +61,7 @@ public static Class analyzeStaticResultType retval = baseType; } else { List> expressionClasses = ObjectUtils.notNull(expressions.stream() - .map(expr -> expr.getStaticResultType()).collect(Collectors.toList())); + .map(IExpression::getStaticResultType).collect(Collectors.toList())); // check if the expression classes, are derived from the base type if (checkDerivedFrom(baseType, expressionClasses)) { diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/For.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/For.java index 41d33a16f..cc87e3219 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/For.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/For.java @@ -79,9 +79,9 @@ public ISequence accept(DynamicContext dynamicContext, ISequenc List retval = new LinkedList<>(); for (IItem item : variableResult) { - subDynamicContext.bindVariableValue(variable.getName().getValue(), ISequence.of(item)); + subDynamicContext.bindVariableValue(variable.getName(), ISequence.of(item)); retval.addAll(getReturnExpression().accept(subDynamicContext, focus)); } - return ISequence.of(retval); + return ISequence.ofCollection(retval); } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/FunctionCallAccessor.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/FunctionCallAccessor.java new file mode 100644 index 000000000..d019f292a --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/FunctionCallAccessor.java @@ -0,0 +1,104 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.cst; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ICollectionValue; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.function.library.ArrayGet; +import gov.nist.secauto.metaschema.core.metapath.function.library.FnData; +import gov.nist.secauto.metaschema.core.metapath.function.library.MapGet; +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.IIntegerItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.IArrayItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.IMapItem; + +import java.util.List; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class FunctionCallAccessor implements IExpression { + @NonNull + private final IExpression base; + @NonNull + private final IExpression argument; + + public FunctionCallAccessor(@NonNull IExpression base, @NonNull IExpression argument) { + this.base = base; + this.argument = argument; + } + + /** + * Get the base sub-expression. + * + * @return the sub-expression + */ + @NonNull + public IExpression getBase() { + return base; + } + + /** + * Retrieve the argument to use for the lookup. + * + * @return the argument + */ + @NonNull + public IExpression getArgument() { + return argument; + } + + @SuppressWarnings("null") + @Override + public List getChildren() { + return List.of(getBase(), getArgument()); + } + + @Override + public ISequence accept(DynamicContext dynamicContext, ISequence focus) { + ISequence target = getBase().accept(dynamicContext, focus); + IItem collection = target.getFirstItem(true); + IAnyAtomicItem key = FnData.fnData(getArgument().accept(dynamicContext, focus)).getFirstItem(false); + + ICollectionValue retval; + if (collection instanceof IArrayItem) { + retval = ArrayGet.get((IArrayItem) collection, IIntegerItem.cast(key)); + } else if (collection instanceof IMapItem) { + retval = MapGet.get((IMapItem) collection, key); + } else { + retval = null; + } + + return retval == null ? ISequence.empty() : retval.asSequence(); + } + + @Override + public RESULT accept(@NonNull IExpressionVisitor visitor, CONTEXT context) { + return visitor.visitFunctionCallAccessor(this, context); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/IExpressionVisitor.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/IExpressionVisitor.java index 054fd958b..007e1ad59 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/IExpressionVisitor.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/IExpressionVisitor.java @@ -37,12 +37,14 @@ import gov.nist.secauto.metaschema.core.metapath.cst.path.Axis; import gov.nist.secauto.metaschema.core.metapath.cst.path.Flag; import gov.nist.secauto.metaschema.core.metapath.cst.path.ModelInstance; +import gov.nist.secauto.metaschema.core.metapath.cst.path.NameTest; import gov.nist.secauto.metaschema.core.metapath.cst.path.RelativeDoubleSlashPath; import gov.nist.secauto.metaschema.core.metapath.cst.path.RelativeSlashPath; import gov.nist.secauto.metaschema.core.metapath.cst.path.RootDoubleSlashPath; import gov.nist.secauto.metaschema.core.metapath.cst.path.RootSlashOnlyPath; import gov.nist.secauto.metaschema.core.metapath.cst.path.RootSlashPath; import gov.nist.secauto.metaschema.core.metapath.cst.path.Step; +import gov.nist.secauto.metaschema.core.metapath.cst.path.Wildcard; import edu.umd.cs.findbugs.annotations.NonNull; @@ -56,6 +58,7 @@ * @param * additional state to pass between nodes visited */ +@SuppressWarnings("PMD.ExcessivePublicCount") public interface IExpressionVisitor { /** @@ -188,7 +191,7 @@ public interface IExpressionVisitor { * the processing context * @return the visitation result or {@code null} if no result was produced */ - RESULT visitFunctionCall(@NonNull FunctionCall expr, @NonNull CONTEXT context); + RESULT visitFunctionCall(@NonNull StaticFunctionCall expr, @NonNull CONTEXT context); /** * Visit the CST node. @@ -276,7 +279,7 @@ public interface IExpressionVisitor { * the processing context * @return the visitation result or {@code null} if no result was produced */ - RESULT visitName(@NonNull Name expr, @NonNull CONTEXT context); + RESULT visitName(@NonNull NameTest expr, @NonNull CONTEXT context); /** * Visit the CST node. @@ -309,7 +312,7 @@ public interface IExpressionVisitor { * the processing context * @return the visitation result or {@code null} if no result was produced */ - RESULT visitPredicate(@NonNull Predicate expr, @NonNull CONTEXT context); + RESULT visitPredicate(@NonNull PredicateExpression expr, @NonNull CONTEXT context); /** * Visit the CST node. @@ -508,4 +511,81 @@ public interface IExpressionVisitor { * @return the visitation result or {@code null} if no result was produced */ RESULT visitSimpleMap(@NonNull SimpleMap expr, @NonNull CONTEXT context); + + /** + * Visit the CST node. + * + * @param expr + * the CST node to visit + * @param context + * the processing context + * @return the visitation result or {@code null} if no result was produced + */ + RESULT visitMapConstructor(@NonNull MapConstructor expr, @NonNull CONTEXT context); + + /** + * Visit the CST node. + * + * @param expr + * the CST node to visit + * @param context + * the processing context + * @return the visitation result or {@code null} if no result was produced + */ + RESULT visitMapConstructorEntry(@NonNull MapConstructor.Entry expr, @NonNull CONTEXT context); + + /** + * Visit the CST node. + * + * @param expr + * the CST node to visit + * @param context + * the processing context + * @return the visitation result or {@code null} if no result was produced + */ + RESULT visitArray(@NonNull ArraySequenceConstructor expr, @NonNull CONTEXT context); + + /** + * Visit the CST node. + * + * @param expr + * the CST node to visit + * @param context + * the processing context + * @return the visitation result or {@code null} if no result was produced + */ + RESULT visitArray(@NonNull ArraySquareConstructor expr, @NonNull CONTEXT context); + + /** + * Visit the CST node. + * + * @param expr + * the CST node to visit + * @param context + * the processing context + * @return the visitation result or {@code null} if no result was produced + */ + RESULT visitPostfixLookup(@NonNull PostfixLookup expr, @NonNull CONTEXT context); + + /** + * Visit the CST node. + * + * @param expr + * the CST node to visit + * @param context + * the processing context + * @return the visitation result or {@code null} if no result was produced + */ + RESULT visitFunctionCallAccessor(@NonNull FunctionCallAccessor expr, @NonNull CONTEXT context); + + /** + * Visit the CST node. + * + * @param expr + * the CST node to visit + * @param context + * the processing context + * @return the visitation result or {@code null} if no result was produced + */ + RESULT visitUnaryLookup(@NonNull UnaryLookup expr, @NonNull CONTEXT context); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Intersect.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Intersect.java index 04999c6de..3a51e26d4 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Intersect.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Intersect.java @@ -56,7 +56,7 @@ public Intersect(@NonNull IExpression left, @NonNull IExpression right) { @Override protected ISequence applyFilterTo(@NonNull ISequence result, @NonNull List items) { - return ISequence.of(result.asStream() + return ISequence.of(result.stream() .distinct() .filter(items::contains)); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Let.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Let.java index bd7389bb4..1568e3fe3 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Let.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Let.java @@ -33,6 +33,8 @@ import java.util.List; +import javax.xml.namespace.QName; + import edu.umd.cs.findbugs.annotations.NonNull; /** @@ -57,7 +59,7 @@ public class Let implements IExpression { * @param returnExpression * the inner expression to evaluate with the variable in-scope */ - public Let(@NonNull Name name, @NonNull IExpression boundExpression, @NonNull IExpression returnExpression) { + public Let(@NonNull QName name, @NonNull IExpression boundExpression, @NonNull IExpression returnExpression) { this.variable = new VariableDeclaration(name, boundExpression); this.returnExpression = returnExpression; } @@ -104,11 +106,11 @@ public ISequence accept(DynamicContext dynamicContext, ISequenc public static class VariableDeclaration { @NonNull - private final Name name; + private final QName name; @NonNull private final IExpression boundExpression; - public VariableDeclaration(@NonNull Name name, @NonNull IExpression boundExpression) { + public VariableDeclaration(@NonNull QName name, @NonNull IExpression boundExpression) { this.name = name; this.boundExpression = boundExpression; } @@ -119,7 +121,7 @@ public VariableDeclaration(@NonNull Name name, @NonNull IExpression boundExpress * @return the variable name */ @NonNull - public Name getName() { + public QName getName() { return name; } @@ -140,8 +142,10 @@ public void bind( ISequence result = getBoundExpression().accept(evalContext, focus); - String name = getName().getValue(); - boundContext.bindVariableValue(name, result); + // ensure this sequence is list backed + result.getValue(); + + boundContext.bindVariableValue(getName(), result); } } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/MapConstructor.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/MapConstructor.java new file mode 100644 index 000000000..61bc9dc42 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/MapConstructor.java @@ -0,0 +1,114 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.cst; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ICollectionValue; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +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.function.IMapItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class MapConstructor implements IExpression { + @NonNull + private final List entries; + + public MapConstructor(@NonNull List entries) { + this.entries = entries; + } + + @Override + public List getChildren() { + return entries; + } + + @Override + public ISequence accept(DynamicContext dynamicContext, ISequence focus) { + return IMapItem.ofCollection( + ObjectUtils.notNull(getChildren().stream() + .map(item -> { + IAnyAtomicItem key + = FnData.fnData(item.getKeyExpression().accept(dynamicContext, focus)).getFirstItem(true); + ICollectionValue value = item.getValueExpression().accept(dynamicContext, focus).toCollectionValue(); + + return IMapItem.entry(key, value); + }).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)))) + .asSequence(); + } + + @Override + public RESULT accept(IExpressionVisitor visitor, CONTEXT context) { + return visitor.visitMapConstructor(this, context); + } + + public static class Entry implements IExpression { + @NonNull + private final IExpression keyExpression; + @NonNull + private final IExpression valueExpression; + + public Entry(@NonNull IExpression keyExpression, @NonNull IExpression valueExpression) { + this.keyExpression = keyExpression; + this.valueExpression = valueExpression; + } + + @NonNull + public IExpression getKeyExpression() { + return keyExpression; + } + + @NonNull + public IExpression getValueExpression() { + return valueExpression; + } + + @SuppressWarnings("null") + @Override + public List getChildren() { + return List.of(keyExpression, valueExpression); + } + + @Override + public ISequence accept(DynamicContext dynamicContext, ISequence focus) { + throw new UnsupportedOperationException("handled by the map constructor"); + } + + @Override + public RESULT accept(IExpressionVisitor visitor, CONTEXT context) { + return visitor.visitMapConstructorEntry(this, context); + } + + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Metapath.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Metapath.java index 8abb5a942..f77150838 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Metapath.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Metapath.java @@ -68,7 +68,7 @@ public ISequence accept(DynamicContext dynamicContext, ISequence focus) { Stream retval = ObjectUtils.notNull(getChildren().stream() .flatMap(child -> { ISequence result = child.accept(dynamicContext, focus); - return result.asStream(); + return result.stream(); })); return ISequence.of(retval); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/PostfixLookup.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/PostfixLookup.java new file mode 100644 index 000000000..1e0108676 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/PostfixLookup.java @@ -0,0 +1,80 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.cst; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ICollectionValue; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.item.IItem; + +import java.util.List; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class PostfixLookup + extends AbstractLookup { + + @NonNull + private final IExpression base; + + public PostfixLookup(@NonNull IExpression base, @NonNull IKeySpecifier keySpecifier) { + super(keySpecifier); + this.base = base; + } + + /** + * Get the base sub-expression. + * + * @return the sub-expression + */ + @NonNull + public IExpression getBase() { + return base; + } + + @SuppressWarnings("null") + @Override + public List getChildren() { + return List.of(getBase()); + } + + @Override + public ISequence accept(DynamicContext dynamicContext, ISequence focus) { + ISequence base = getBase().accept(dynamicContext, focus); + + IKeySpecifier specifier = getKeySpecifier(); + + return ISequence.of(base.stream() + .flatMap(item -> specifier.lookup(item, dynamicContext, focus)) + .flatMap(ICollectionValue::normalizeAsItems)); + } + + @Override + public RESULT accept(@NonNull IExpressionVisitor visitor, CONTEXT context) { + return visitor.visitPostfixLookup(this, context); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Predicate.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/PredicateExpression.java similarity index 95% rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Predicate.java rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/PredicateExpression.java index 7881452e7..cca0a474c 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Predicate.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/PredicateExpression.java @@ -36,13 +36,14 @@ import java.math.BigInteger; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import java.util.stream.Stream; import edu.umd.cs.findbugs.annotations.NonNull; -public class Predicate implements IExpression { +public class PredicateExpression implements IExpression { @NonNull private final IExpression base; @NonNull @@ -56,7 +57,7 @@ public class Predicate implements IExpression { * @param predicates * the expression(s) to apply as a filter */ - public Predicate(@NonNull IExpression base, @NonNull List predicates) { + public PredicateExpression(@NonNull IExpression base, @NonNull List predicates) { this.base = base; this.predicates = predicates; } @@ -98,7 +99,7 @@ public List getChildren() { AtomicInteger index = new AtomicInteger(); Stream stream = ObjectUtils.notNull( - retval.asStream().map(item -> { + retval.stream().map(item -> { // build a positional index of the items return Map.entry(BigInteger.valueOf(index.incrementAndGet()), item); }).filter(entry -> { @@ -125,7 +126,7 @@ public List getChildren() { } return bool; }).anyMatch(x -> !x); - }).map(entry -> entry.getValue())); + }).map(Entry::getValue)); retval = ISequence.of(stream); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Quantified.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Quantified.java index 04093a970..8a414cee0 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Quantified.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Quantified.java @@ -44,6 +44,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import javax.xml.namespace.QName; + import edu.umd.cs.findbugs.annotations.NonNull; public class Quantified @@ -56,7 +58,7 @@ public enum Quantifier { @NonNull private final Quantifier quantifier; @NonNull - private final Map inClauses; + private final Map inClauses; @NonNull private final IExpression satisfies; @@ -74,7 +76,7 @@ public enum Quantifier { */ public Quantified( @NonNull Quantifier quantifier, - @NonNull Map inClauses, + @NonNull Map inClauses, @NonNull IExpression satisfies) { this.quantifier = quantifier; this.inClauses = inClauses; @@ -98,7 +100,7 @@ public Quantifier getQuantifier() { * @return the variable names mapped to the associated Metapath expression */ @NonNull - public Map getInClauses() { + public Map getInClauses() { return inClauses; } @@ -122,20 +124,20 @@ public List getChildren() { @SuppressWarnings("PMD.SystemPrintln") @Override public ISequence accept(DynamicContext dynamicContext, ISequence focus) { - Map> clauses = getInClauses().entrySet().stream() + Map> clauses = getInClauses().entrySet().stream() .map(entry -> Map.entry( entry.getKey(), entry.getValue().accept(dynamicContext, focus))) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)); - List clauseKeys = new ArrayList<>(clauses.keySet()); + List clauseKeys = new ArrayList<>(clauses.keySet()); List> clauseValues = new ArrayList<>(clauses.values()); boolean retval = true; for (List product : new CartesianProduct<>(clauseValues)) { DynamicContext subDynamicContext = dynamicContext.subContext(); for (int idx = 0; idx < product.size(); idx++) { - String var = clauseKeys.get(idx); + QName var = clauseKeys.get(idx); IItem item = product.get(idx); assert var != null; diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Range.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Range.java index a0914210e..f89d13286 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Range.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Range.java @@ -84,7 +84,7 @@ public ISequence accept(DynamicContext dynamicContext, ISequence accept(DynamicContext dynamicContext, ISequence focus) { IExpression right = getRight(); return ObjectUtils.notNull(leftResult.stream() - .flatMap(item -> right.accept(dynamicContext, ISequence.of(item)).asStream()) + .flatMap(item -> right.accept(dynamicContext, ISequence.of(item)).stream()) .collect(ISequence.toSequence())); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/FunctionCall.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/StaticFunctionCall.java similarity index 95% rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/FunctionCall.java rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/StaticFunctionCall.java index dbdcf6ea9..9660aeaa3 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/FunctionCall.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/StaticFunctionCall.java @@ -38,11 +38,13 @@ import java.util.Objects; import java.util.stream.Collectors; +import javax.xml.namespace.QName; + import edu.umd.cs.findbugs.annotations.NonNull; -public class FunctionCall implements IExpression { +public class StaticFunctionCall implements IExpression { @NonNull - private final String name; + private final QName name; @NonNull private final List arguments; private IFunction function; @@ -55,7 +57,7 @@ public class FunctionCall implements IExpression { * @param arguments * the expressions used to provide arguments to the function call */ - public FunctionCall(@NonNull String name, @NonNull List arguments) { + public StaticFunctionCall(@NonNull QName name, @NonNull List arguments) { this.name = Objects.requireNonNull(name, "name"); this.arguments = Objects.requireNonNull(arguments, "arguments"); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/StringConcat.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/StringConcat.java index 2f7c36f27..757163ee9 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/StringConcat.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/StringConcat.java @@ -71,7 +71,7 @@ public ISequence accept(DynamicContext dynamicContext, ISequence focus) { StringBuilder builder = new StringBuilder(); for (IExpression child : getChildren()) { ISequence result = child.accept(dynamicContext, focus); - FnData.fnData(result).asStream() + FnData.fnData(result).stream() .forEachOrdered(item -> { builder.append(item.asString()); }); diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/UnaryLookup.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/UnaryLookup.java new file mode 100644 index 000000000..2e2bb0d07 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/UnaryLookup.java @@ -0,0 +1,64 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.cst; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ICollectionValue; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.item.IItem; + +import java.util.List; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class UnaryLookup + extends AbstractLookup { + + public UnaryLookup(@NonNull IKeySpecifier keySpecifier) { + super(keySpecifier); + } + + @SuppressWarnings("null") + @Override + public List getChildren() { + return List.of(); + } + + @Override + public ISequence accept(DynamicContext dynamicContext, ISequence focus) { + IKeySpecifier specifier = getKeySpecifier(); + + return ISequence.of(focus.stream() + .flatMap(item -> specifier.lookup(item, dynamicContext, focus)) + .flatMap(ICollectionValue::normalizeAsItems)); + } + + @Override + public RESULT accept(@NonNull IExpressionVisitor visitor, CONTEXT context) { + return visitor.visitUnaryLookup(this, context); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Union.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Union.java index 7eaacd691..ab8be293f 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Union.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Union.java @@ -70,11 +70,14 @@ public RESULT accept(IExpressionVisitor visit @Override public ISequence accept(DynamicContext dynamicContext, ISequence focus) { - focus.collect(); + // ensure the sequence is backed by a list + focus.getValue(); + + // now process the union @NonNull Stream retval = ObjectUtils.notNull(getChildren().stream() .flatMap(child -> { ISequence result = child.accept(dynamicContext, focus); - return result.asStream(); + return result.stream(); }).distinct()); return ISequence.of(retval); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/VariableReference.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/VariableReference.java index 9cd5beb7e..959861c84 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/VariableReference.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/VariableReference.java @@ -34,6 +34,8 @@ import java.util.List; +import javax.xml.namespace.QName; + import edu.umd.cs.findbugs.annotations.NonNull; /** @@ -43,7 +45,7 @@ */ public class VariableReference implements IExpression { @NonNull - private final Name name; + private final QName name; /** * Construct a new Metapath variable reference CST node. @@ -51,7 +53,7 @@ public class VariableReference implements IExpression { * @param name * the variable name */ - public VariableReference(@NonNull Name name) { + public VariableReference(@NonNull QName name) { this.name = name; } @@ -61,7 +63,7 @@ public VariableReference(@NonNull Name name) { * @return the variable name */ @NonNull - public Name getName() { + public QName getName() { return name; } @@ -73,7 +75,7 @@ public List getChildren() { @SuppressWarnings("null") @Override public String toASTString() { - return String.format("%s[name=%s]", getClass().getName(), getName().getValue()); + return String.format("%s[name=%s]", getClass().getName(), getName()); } @Override @@ -83,7 +85,7 @@ public RESULT accept(IExpressionVisitor visit @Override public ISequence accept(DynamicContext dynamicContext, ISequence focus) { - return dynamicContext.getVariableValue(ObjectUtils.notNull(getName().getValue())); + return dynamicContext.getVariableValue(ObjectUtils.notNull(getName())); } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/AbstractPathExpression.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/AbstractPathExpression.java index 410e900f0..e0354e852 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/AbstractPathExpression.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/AbstractPathExpression.java @@ -68,15 +68,15 @@ protected Stream searchExpression( @NonNull IExpression expression, @NonNull DynamicContext dynamicContext, @NonNull ISequence outerFocus) { - - outerFocus.collect(); + // ensure the sequence is backed by a list + outerFocus.getValue(); // check the current focus @SuppressWarnings("unchecked") Stream nodeMatches - = (Stream) expression.accept(dynamicContext, outerFocus).asStream(); + = (Stream) expression.accept(dynamicContext, outerFocus).stream(); - Stream childMatches = outerFocus.asStream() - .map(item -> ItemUtils.checkItemIsNodeItemForStep(item)) + Stream childMatches = outerFocus.stream() + .map(ItemUtils::checkItemIsNodeItemForStep) .flatMap(focusedNode -> { Stream matches; diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/Axis.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/Axis.java index 1895941a9..d9f61f15c 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/Axis.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/Axis.java @@ -43,7 +43,7 @@ @SuppressWarnings("PMD.ShortClassName") // intentional public enum Axis implements IExpression { - SELF(focus -> Stream.of(focus)), + SELF(Stream::of), PARENT(focus -> Stream.ofNullable(focus.getParentNodeItem())), ANCESTOR(INodeItem::ancestor), ANCESTOR_OR_SELF(INodeItem::ancestorOrSelf), @@ -98,8 +98,8 @@ public ISequence accept( if (outerFocus.isEmpty()) { retval = ISequence.empty(); } else { - retval = ISequence.of(outerFocus.asStream() - .map(item -> ItemUtils.checkItemIsNodeItemForStep(item)) + retval = ISequence.of(outerFocus.stream() + .map(ItemUtils::checkItemIsNodeItemForStep) .flatMap(item -> { assert item != null; return execute(item); diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/Flag.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/Flag.java index 60d9e2a46..e04f6a13d 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/Flag.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/Flag.java @@ -31,13 +31,14 @@ import gov.nist.secauto.metaschema.core.metapath.cst.AbstractNamedInstanceExpression; import gov.nist.secauto.metaschema.core.metapath.cst.IExpression; import gov.nist.secauto.metaschema.core.metapath.cst.IExpressionVisitor; -import gov.nist.secauto.metaschema.core.metapath.cst.Name; import gov.nist.secauto.metaschema.core.metapath.item.ItemUtils; import gov.nist.secauto.metaschema.core.metapath.item.node.IFlagNodeItem; import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem; import java.util.stream.Stream; +import javax.xml.namespace.QName; + import edu.umd.cs.findbugs.annotations.NonNull; public class Flag // NOPMD - intentional name @@ -68,8 +69,8 @@ public RESULT accept(IExpressionVisitor visit public ISequence accept( DynamicContext dynamicContext, ISequence focus) { - return ISequence.of(focus.asStream() - .map(item -> ItemUtils.checkItemIsNodeItemForStep(item)) + return ISequence.of(focus.stream() + .map(ItemUtils::checkItemIsNodeItemForStep) .flatMap(item -> { assert item != null; return match(item); @@ -87,8 +88,8 @@ public ISequence accept( @NonNull protected Stream match(@NonNull INodeItem focusedItem) { Stream retval; - if (getTest() instanceof Name) { - String name = ((Name) getTest()).getValue(); + if (getTest() instanceof NameTest) { + QName name = ((NameTest) getTest()).getName(); IFlagNodeItem item = focusedItem.getFlagByName(name); retval = item == null ? Stream.empty() : Stream.of(item); diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/IBindingContainerModelAssembly.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/INameTestExpression.java similarity index 75% rename from databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/IBindingContainerModelAssembly.java rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/INameTestExpression.java index 47f9d2144..992a5211e 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/IBindingContainerModelAssembly.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/INameTestExpression.java @@ -24,21 +24,28 @@ * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. */ -package gov.nist.secauto.metaschema.databind.model.metaschema; +package gov.nist.secauto.metaschema.core.metapath.cst.path; -import gov.nist.secauto.metaschema.core.model.IContainerModelAssembly; +import gov.nist.secauto.metaschema.core.metapath.cst.IExpression; +import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem; +import java.util.Collections; import java.util.List; -import java.util.Map; - -public interface IBindingContainerModelAssembly extends IContainerModelAssembly, IBindingContainerModelAbsolute { +public interface INameTestExpression extends INodeTestExpression { + @SuppressWarnings("null") @Override - List getChoiceInstances(); + default List getChildren() { + return Collections.emptyList(); + } @Override - IInstanceModelChoiceGroupBinding getChoiceGroupInstanceByName(String name); + default Class getBaseResultType() { + return INodeItem.class; + } @Override - Map getChoiceGroupInstances(); + default Class getStaticResultType() { + return getBaseResultType(); + } } diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/IBindingInstanceFlag.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/INodeTestExpression.java similarity index 89% rename from databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/IBindingInstanceFlag.java rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/INodeTestExpression.java index 6c127ea7b..b5bd5bed1 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/IBindingInstanceFlag.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/INodeTestExpression.java @@ -24,10 +24,10 @@ * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. */ -package gov.nist.secauto.metaschema.databind.model.metaschema; +package gov.nist.secauto.metaschema.core.metapath.cst.path; -import gov.nist.secauto.metaschema.core.model.IFlagInstance; +import gov.nist.secauto.metaschema.core.metapath.cst.IExpression; -public interface IBindingInstanceFlag extends IFlagInstance, IBindingInstance { +public interface INodeTestExpression extends IExpression { // no additional methods } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/ModelInstance.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/ModelInstance.java index f63c0a7f6..c1ee8298a 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/ModelInstance.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/ModelInstance.java @@ -31,7 +31,6 @@ import gov.nist.secauto.metaschema.core.metapath.cst.AbstractNamedInstanceExpression; import gov.nist.secauto.metaschema.core.metapath.cst.IExpression; import gov.nist.secauto.metaschema.core.metapath.cst.IExpressionVisitor; -import gov.nist.secauto.metaschema.core.metapath.cst.Name; import gov.nist.secauto.metaschema.core.metapath.item.ItemUtils; import gov.nist.secauto.metaschema.core.metapath.item.node.IModelNodeItem; import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem; @@ -39,6 +38,8 @@ import java.util.List; import java.util.stream.Stream; +import javax.xml.namespace.QName; + import edu.umd.cs.findbugs.annotations.NonNull; @SuppressWarnings("rawtypes") @@ -70,8 +71,8 @@ public RESULT accept(IExpressionVisitor visit public ISequence> accept( DynamicContext dynamicContext, ISequence focus) { - return ISequence.of(focus.asStream() - .map(item -> ItemUtils.checkItemIsNodeItemForStep(item)) + return ISequence.of(focus.stream() + .map(ItemUtils::checkItemIsNodeItemForStep) .flatMap(item -> { assert item != null; return match(item); @@ -90,8 +91,8 @@ public RESULT accept(IExpressionVisitor visit protected Stream> match( @NonNull INodeItem focusedItem) { Stream> retval; - if (getTest() instanceof Name) { - String name = ((Name) getTest()).getValue(); + if (getTest() instanceof NameTest) { + QName name = ((NameTest) getTest()).getName(); List> items = focusedItem.getModelItemsByName(name); retval = items.stream(); } else { diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Name.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/NameTest.java similarity index 76% rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Name.java rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/NameTest.java index 2760a5849..884d7491f 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/Name.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/NameTest.java @@ -24,16 +24,16 @@ * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. */ -package gov.nist.secauto.metaschema.core.metapath.cst; +package gov.nist.secauto.metaschema.core.metapath.cst.path; import gov.nist.secauto.metaschema.core.metapath.DynamicContext; import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.cst.IExpressionVisitor; import gov.nist.secauto.metaschema.core.metapath.item.ItemUtils; import gov.nist.secauto.metaschema.core.metapath.item.node.IDefinitionNodeItem; import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem; -import gov.nist.secauto.metaschema.core.util.CollectionUtil; -import java.util.List; +import javax.xml.namespace.QName; import edu.umd.cs.findbugs.annotations.NonNull; @@ -42,20 +42,20 @@ * expanded QName * name test. */ -public class Name // NOPMD - intentional - implements IExpression { +public class NameTest + implements INameTestExpression { @NonNull - private final String value; + private final QName name; /** * Construct a new expanded QName-based literal expression. * - * @param value + * @param name * the literal value */ - public Name(@NonNull String value) { - this.value = value; + public NameTest(@NonNull QName name) { + this.name = name; } /** @@ -64,23 +64,8 @@ public Name(@NonNull String value) { * @return the string value of the name */ @NonNull - public String getValue() { - return value; - } - - @Override - public List getChildren() { - return CollectionUtil.emptyList(); - } - - @Override - public Class getBaseResultType() { - return INodeItem.class; - } - - @Override - public Class getStaticResultType() { - return getBaseResultType(); + public QName getName() { + return name; } @Override @@ -92,20 +77,20 @@ public RESULT accept(IExpressionVisitor visit public ISequence accept( DynamicContext dynamicContext, ISequence focus) { - return ISequence.of(focus.asStream() - .map(item -> ItemUtils.checkItemIsNodeItemForStep(item)) + return ISequence.of(focus.stream() + .map(ItemUtils::checkItemIsNodeItemForStep) .filter(this::match)); } @SuppressWarnings("PMD.UnusedPrivateMethod") private boolean match(INodeItem item) { return item instanceof IDefinitionNodeItem - && getValue().equals(((IDefinitionNodeItem) item).getName()); + && getName().equals(((IDefinitionNodeItem) item).getName()); } @SuppressWarnings("null") @Override public String toASTString() { - return String.format("%s[value=%s]", getClass().getName(), getValue()); + return String.format("%s[name=%s]", getClass().getName(), getName()); } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/RelativeSlashPath.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/RelativeSlashPath.java index f65b0ba61..1b52e18a4 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/RelativeSlashPath.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/RelativeSlashPath.java @@ -60,6 +60,9 @@ public ISequence accept( ISequence focus) { ISequence leftResult = getLeft().accept(dynamicContext, focus); + // ensure the left sequence is list backed + leftResult.getValue(); + return getRight().accept(dynamicContext, leftResult); } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/RootSlashOnlyPath.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/RootSlashOnlyPath.java index c5e5902ea..aa0d0688e 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/RootSlashOnlyPath.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/RootSlashOnlyPath.java @@ -60,8 +60,8 @@ public ISequence accept( DynamicContext dynamicContext, ISequence focus) { - return ObjectUtils.notNull(focus.asStream() - .map(item -> ItemUtils.checkItemIsNodeItemForStep(item)) + return ObjectUtils.notNull(focus.stream() + .map(ItemUtils::checkItemIsNodeItemForStep) .map(item -> Axis.ANCESTOR_OR_SELF.execute(ObjectUtils.notNull(item)).findFirst().get()) .collect(ISequence.toSequence())); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/RootSlashPath.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/RootSlashPath.java index c33b16189..4d0cec884 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/RootSlashPath.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/RootSlashPath.java @@ -59,9 +59,10 @@ public ISequence accept( DynamicContext dynamicContext, ISequence focus) { - ISequence roots = ObjectUtils.notNull(focus.asStream() - .map(item -> ItemUtils.checkItemIsNodeItemForStep(item)) - .map(item -> Axis.ANCESTOR_OR_SELF.execute(ObjectUtils.notNull(item)).findFirst().get()) + ISequence roots = ObjectUtils.notNull(focus.stream() + .map(ItemUtils::checkItemIsNodeItemForStep) + // the previous checks for a null instance + .flatMap(item -> Axis.ANCESTOR_OR_SELF.execute(ObjectUtils.notNull(item)).limit(1)) .collect(ISequence.toSequence())); return getExpression().accept(dynamicContext, roots); diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/Step.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/Step.java index 41178b2ae..5e398af78 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/Step.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/Step.java @@ -49,7 +49,7 @@ public class Step implements IExpression { // NOPMD - intentional @NonNull private final Axis axisExpression; @NonNull - private final IExpression stepExpression; + private final INodeTestExpression stepExpression; @NonNull private final Class staticResultType; @@ -62,7 +62,7 @@ public class Step implements IExpression { // NOPMD - intentional * the sub-expression to evaluate before filtering with the predicates */ @SuppressWarnings("null") - public Step(@NonNull Axis axis, @NonNull IExpression step) { + public Step(@NonNull Axis axis, @NonNull INodeTestExpression step) { this.axisExpression = axis; this.stepExpression = step; this.staticResultType = ExpressionUtils.analyzeStaticResultType(IItem.class, List.of(step)); @@ -84,7 +84,7 @@ public Axis getAxis() { * @return the sub-expression */ @NonNull - public IExpression getStep() { + public INodeTestExpression getStep() { return stepExpression; } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/Wildcard.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/Wildcard.java new file mode 100644 index 000000000..81a7a6ab6 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/path/Wildcard.java @@ -0,0 +1,102 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.cst.path; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.cst.IExpressionVisitor; +import gov.nist.secauto.metaschema.core.metapath.item.ItemUtils; +import gov.nist.secauto.metaschema.core.metapath.item.node.IDefinitionNodeItem; +import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem; + +import java.util.function.Predicate; +import java.util.stream.Stream; + +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; + +/** + * The CST node for a Metapath + * wildcard name + * test. + */ +public class Wildcard implements INameTestExpression { + @Nullable + private final Predicate> matcher; + + public Wildcard(@Nullable Predicate> matcher) { + this.matcher = matcher; + } + + @Override + public RESULT accept(IExpressionVisitor visitor, CONTEXT context) { + return visitor.visitWildcard(this, context); + } + + @Override + public ISequence accept( + DynamicContext dynamicContext, ISequence focus) { + Stream nodes = focus.stream().map(ItemUtils::checkItemIsNodeItemForStep); + if (matcher != null) { + Predicate> test = matcher; + nodes = nodes.filter(item -> { + assert matcher != null; + return !(item instanceof IDefinitionNodeItem) || + test.test((IDefinitionNodeItem) item); + }); + } + return ISequence.of(nodes); + } + + public static class MatchAnyNamespace implements Predicate> { + @NonNull + private final String localName; + + public MatchAnyNamespace(@NonNull String localName) { + this.localName = localName; + } + + @Override + public boolean test(IDefinitionNodeItem item) { + return localName.equals(item.getName().getLocalPart()); + } + } + + public static class MatchAnyLocalName implements Predicate> { + @NonNull + private final String namespace; + + public MatchAnyLocalName(@NonNull String namespace) { + this.namespace = namespace; + } + + @Override + public boolean test(IDefinitionNodeItem item) { + return namespace.equals(item.getName().getNamespaceURI()); + } + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/format/MetapathFormatter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/format/MetapathFormatter.java index 48af77792..2b1cf765f 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/format/MetapathFormatter.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/format/MetapathFormatter.java @@ -35,6 +35,7 @@ import gov.nist.secauto.metaschema.core.metapath.item.node.IModuleNodeItem; import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem; import gov.nist.secauto.metaschema.core.metapath.item.node.IRootAssemblyNodeItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; import edu.umd.cs.findbugs.annotations.NonNull; @@ -60,7 +61,7 @@ public String formatDocument(IDocumentNodeItem document) { @Override public String formatRootAssembly(IRootAssemblyNodeItem root) { - return root.getName(); + return ObjectUtils.notNull(root.getName().getLocalPart()); } @Override @@ -88,7 +89,7 @@ public String formatFlag(IFlagNodeItem flag) { @SuppressWarnings("null") @NonNull private static String formatModelPathSegment(@NonNull IModelNodeItem item) { - StringBuilder builder = new StringBuilder(item.getName()) + StringBuilder builder = new StringBuilder(item.getName().getLocalPart()) .append('[') .append(item.getPosition()) .append(']'); diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/AbstractFunction.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/AbstractFunction.java index d639a5ec1..b9237cdff 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/AbstractFunction.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/AbstractFunction.java @@ -28,13 +28,13 @@ import java.util.List; +import javax.xml.namespace.QName; + import edu.umd.cs.findbugs.annotations.NonNull; abstract class AbstractFunction implements IFunction { @NonNull - private final String name; - @NonNull - private final String namespace; + private final QName qname; @NonNull private final List arguments; @@ -42,19 +42,19 @@ protected AbstractFunction( @NonNull String name, @NonNull String namespace, @NonNull List arguments) { - this.name = name; - this.namespace = namespace; - this.arguments = arguments; + this(new QName(namespace, name), arguments); } - @Override - public String getName() { - return name; + protected AbstractFunction( + @NonNull QName qname, + @NonNull List arguments) { + this.qname = qname; + this.arguments = arguments; } @Override - public String getNamespace() { - return namespace; + public QName getQName() { + return qname; } @Override diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/ArithmeticFunctionException.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/ArithmeticFunctionException.java index 0e153d284..cfde0d34c 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/ArithmeticFunctionException.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/ArithmeticFunctionException.java @@ -96,7 +96,7 @@ public ArithmeticFunctionException(int code, Throwable cause) { } @Override - protected String getCodePrefix() { + public String getCodePrefix() { return "FOAR"; } 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 dc2c82e91..81182def0 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 @@ -117,9 +117,9 @@ public static IBooleanItem generalCompairison( // NOPMD - acceptable complexity @NonNull ISequence rightItems) { IBooleanItem retval = IBooleanItem.FALSE; - for (IAnyAtomicItem left : leftItems.asList()) { + for (IAnyAtomicItem left : leftItems.getValue()) { assert left != null; - for (IAnyAtomicItem right : rightItems.asList()) { + for (IAnyAtomicItem right : rightItems.getValue()) { assert right != null; IAnyAtomicItem leftCast; IAnyAtomicItem rightCast; diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/DateTimeFunctionException.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/DateTimeFunctionException.java index a67b5f508..38c007e78 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/DateTimeFunctionException.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/DateTimeFunctionException.java @@ -102,7 +102,7 @@ public DateTimeFunctionException(int code, Throwable cause) { } @Override - protected String getCodePrefix() { + public String getCodePrefix() { return "FODT"; } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/DefaultFunction.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/DefaultFunction.java index 8907d8d66..3d2151e1a 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/DefaultFunction.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/DefaultFunction.java @@ -35,6 +35,7 @@ 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.IStringItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; import java.util.ArrayList; import java.util.Collections; @@ -43,7 +44,7 @@ import java.util.List; import java.util.Objects; import java.util.Set; -import java.util.stream.Collectors; +import java.util.stream.Stream; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; @@ -206,7 +207,7 @@ public static List> convertArguments( String.format("a sequence of one expected, but found '%d'", size)); } - IItem item = FunctionUtils.getFirstItem(parameter, true); + IItem item = parameter.getFirstItem(true); parameter = item == null ? ISequence.empty() : ISequence.of(item); break; } @@ -217,7 +218,7 @@ public static List> convertArguments( String.format("a sequence of zero or one expected, but found '%d'", size)); } - IItem item = FunctionUtils.getFirstItem(parameter, false); + IItem item = parameter.getFirstItem(false); parameter = item == null ? ISequence.empty() : ISequence.of(item); break; } @@ -246,7 +247,7 @@ public static List> convertArguments( parameter = convertSequence(argument, parameter); // check resulting values - for (IItem item : parameter.asList()) { + for (IItem item : parameter.getValue()) { Class itemClass = item.getClass(); if (!argumentClass.isAssignableFrom(itemClass)) { throw new InvalidTypeMetapathException( @@ -280,35 +281,34 @@ protected static ISequence convertSequence(@NonNull IArgument argument, @NonN ISequenceType requiredSequenceType = argument.getSequenceType(); Class requiredSequenceTypeClass = requiredSequenceType.getType(); - List result = new ArrayList<>(sequence.size()); + Stream stream = sequence.safeStream(); - boolean atomize = IAnyAtomicItem.class.isAssignableFrom(requiredSequenceTypeClass); + if (IAnyAtomicItem.class.isAssignableFrom(requiredSequenceTypeClass)) { + Stream atomicStream = stream.flatMap(FnData::atomize); - for (IItem item : sequence.asList()) { - assert item != null; - if (atomize) { - item = FnData.fnDataItem(item); // NOPMD - intentional - - // if (IUntypedAtomicItem.class.isInstance(item)) { // NOPMD - // // TODO: apply cast to atomic type - // } + // if (IUntypedAtomicItem.class.isInstance(item)) { // NOPMD + // // TODO: apply cast to atomic type + // } + if (IStringItem.class.equals(requiredSequenceTypeClass)) { // promote URIs to strings if a string is required - if (IStringItem.class.equals(requiredSequenceTypeClass) && IAnyUriItem.class.isInstance(item)) { - item = IStringItem.cast((IAnyUriItem) item); // NOPMD - intentional - } + atomicStream = atomicStream.map(item -> IAnyUriItem.class.isInstance(item) ? IStringItem.cast(item) : item); } - // item = requiredSequenceType. + stream = atomicStream; + } + + stream = stream.peek(item -> { if (!requiredSequenceTypeClass.isInstance(item)) { throw new InvalidTypeMetapathException( item, - String.format("The type '%s' is not a subtype of '%s'", item.getClass().getName(), + String.format("The type '%s' is not a subtype of '%s'", + item.getClass().getName(), requiredSequenceTypeClass.getName())); } - result.add(item); - } - retval = ISequence.of(result); + }); + + retval = ISequence.of(stream); } return retval; } @@ -321,7 +321,7 @@ public ISequence execute( try { List> convertedArguments = convertArguments(this, arguments); - IItem contextItem = isFocusDepenent() ? FunctionUtils.requireFirstItem(focus, true) : null; + IItem contextItem = isFocusDepenent() ? ObjectUtils.requireNonNull(focus.getFirstItem(true)) : null; CallingContext callingContext = null; ISequence result = null; @@ -381,32 +381,6 @@ public String toString() { return toSignature(); } - @Override - public String toSignature() { - StringBuilder builder = new StringBuilder() - .append("Q{") - .append(getNamespace()) - .append('}') - .append(getName()) // name - .append('('); // arguments - - List arguments = getArguments(); - if (arguments.isEmpty()) { - builder.append("()"); - } else { - builder.append(arguments.stream().map(argument -> argument.toSignature()).collect(Collectors.joining(","))); - - if (isArityUnbounded()) { - builder.append(", ..."); - } - } - - builder.append(") as ") - .append(getResult().toSignature());// return type - - return builder.toString(); - } - public final class CallingContext { @Nullable private final IItem contextItem; diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/DocumentFunctionException.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/DocumentFunctionException.java index cef0f0aa3..9f35470c0 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/DocumentFunctionException.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/DocumentFunctionException.java @@ -104,7 +104,7 @@ public DocumentFunctionException(int code, Throwable cause) { } @Override - protected String getCodePrefix() { + public String getCodePrefix() { return "FODC"; } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/FunctionLibrary.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/FunctionLibrary.java index 739059485..5e0c4463f 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/FunctionLibrary.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/FunctionLibrary.java @@ -53,7 +53,7 @@ public class FunctionLibrary implements IFunctionLibrary { * if the provided function has the same arity as a previously * registered function with the same name */ - public void registerFunction(@NonNull IFunction function) { + public final void registerFunction(@NonNull IFunction function) { registerFunctionByQName(function); registerFunctionByName(function); } @@ -89,12 +89,9 @@ private void registerFunctionByName(@NonNull IFunction function) { } @Override - public Stream getFunctionsAsStream() { + public Stream stream() { synchronized (this) { - return ObjectUtils.notNull( - libraryByQName.values().stream().flatMap(set -> { - return set.getFunctionsAsStream(); - })); + return ObjectUtils.notNull(libraryByQName.values().stream().flatMap(NamedFunctionSet::getFunctionsAsStream)); } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/FunctionService.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/FunctionService.java index 07c94382e..3e27244d2 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/FunctionService.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/FunctionService.java @@ -31,6 +31,7 @@ import java.util.ServiceLoader; import java.util.ServiceLoader.Provider; +import java.util.stream.Stream; import javax.xml.namespace.QName; @@ -42,7 +43,7 @@ public final class FunctionService { @NonNull private final ServiceLoader loader; @NonNull - private IFunctionLibrary library; + private final IFunctionLibrary library; /** * Get the singleton instance of the function service. @@ -59,30 +60,14 @@ public static FunctionService getInstance() { @SuppressWarnings("null") public FunctionService() { this.loader = ServiceLoader.load(IFunctionLibrary.class); - this.library = load(); - } - - /** - * Load all known functions registered with this function service. - * - * @return the function library - */ - @NonNull - public IFunctionLibrary load() { ServiceLoader loader = getLoader(); FunctionLibrary functionLibrary = new FunctionLibrary(); loader.stream() .map(Provider::get) - .flatMap(library -> { - return library.getFunctionsAsStream(); - }) + .flatMap(IFunctionLibrary::stream) .forEachOrdered(function -> functionLibrary.registerFunction(ObjectUtils.notNull(function))); - - synchronized (this) { - this.library = functionLibrary; - } - return functionLibrary; + this.library = functionLibrary; } /** @@ -95,6 +80,10 @@ private ServiceLoader getLoader() { return loader; } + public Stream stream() { + return this.library.stream(); + } + /** * Retrieve the function with the provided name that supports the signature of * the provided methods, if such a function exists. 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 3a9790afe..73d7dca75 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 @@ -112,74 +112,6 @@ public static long asLong(@NonNull BigInteger value) { return value.longValueExact(); } - /** - * Retrieves the first item in a sequence. If the sequence is empty, a - * {@link TypeMetapathException} exception is thrown. If requireSingleton is - * {@code true} and the sequence contains more than one item, a - * {@link TypeMetapathException} is thrown. - * - * @param - * the item type to return derived from the provided sequence - * @param sequence - * the sequence to retrieve the first item from - * @param requireSingleton - * if {@code true} then a {@link TypeMetapathException} is thrown if - * the sequence contains more than one item - * @return {@code null} if the sequence is empty, or the item otherwise - * @throws TypeMetapathException - * if the sequence is empty, or contains more than one item and - * requireSingleton is {@code true} - */ - @NonNull - public static ITEM requireFirstItem(@NonNull ISequence sequence, - boolean requireSingleton) { - if (sequence.isEmpty()) { - throw new InvalidTypeMetapathException( - null, - "Expected a non-empty sequence, but sequence was empty."); - } - List items = sequence.asList(); - if (requireSingleton && items.size() != 1) { - throw new InvalidTypeMetapathException( - null, - String.format("sequence expected to contain one item, but found '%d'", items.size())); - } - return ObjectUtils.notNull(items.iterator().next()); - } - - /** - * Retrieves the first item in a sequence. If the sequence is empty, a - * {@code null} result is returned. If requireSingleton is {@code true} and the - * sequence contains more than one item, a {@link TypeMetapathException} is - * thrown. - * - * @param - * the item type to return derived from the provided sequence - * @param sequence - * the sequence to retrieve the first item from - * @param requireSingleton - * if {@code true} then a {@link TypeMetapathException} is thrown if - * the sequence contains more than one item - * @return {@code null} if the sequence is empty, or the item otherwise - * @throws TypeMetapathException - * if the sequence contains more than one item and requireSingleton is - * {@code true} - */ - @Nullable - public static ITEM getFirstItem(@NonNull ISequence sequence, boolean requireSingleton) { - @Nullable ITEM retval = null; - if (!sequence.isEmpty()) { - List items = sequence.asList(); - if (requireSingleton && items.size() != 1) { - throw new InvalidTypeMetapathException( - null, - String.format("sequence expected to contain one item, but found '%d'", items.size())); - } - retval = items.iterator().next(); - } - return retval; - } - /** * Gets the first item of the provided sequence as a {@link INumericItem} value. * If the sequence is empty, then a {@code null} value is returned. @@ -198,7 +130,7 @@ public static ITEM getFirstItem(@NonNull ISequence se */ @Nullable public static INumericItem toNumeric(@NonNull ISequence sequence, boolean requireSingleton) { - IItem item = getFirstItem(sequence, requireSingleton); + IItem item = sequence.getFirstItem(requireSingleton); return item == null ? null : toNumeric(item); } @@ -215,7 +147,7 @@ public static INumericItem toNumeric(@NonNull ISequence sequence, boolean req @NonNull public static INumericItem toNumeric(@NonNull IItem item) { // atomize - IAnyAtomicItem atomicItem = FnData.fnDataItem(item); + IAnyAtomicItem atomicItem = ISequence.getFirstItem(FnData.atomize(item), true); return toNumeric(atomicItem); } @@ -229,7 +161,7 @@ public static INumericItem toNumeric(@NonNull IItem item) { * if the item cannot be cast to a numeric value */ @NonNull - public static INumericItem toNumeric(@NonNull IAnyAtomicItem item) { + public static INumericItem toNumeric(@Nullable IAnyAtomicItem item) { try { return IDecimalItem.cast(item); } catch (InvalidValueForCastFunctionException ex) { @@ -373,7 +305,7 @@ public static TYPE requireTypeOrNull(Class clazz, @Nu */ @NonNull public static Stream> getTypes(@NonNull Stream items) { - return ObjectUtils.notNull(items.map(item -> item.getClass())); + return ObjectUtils.notNull(items.map(Object::getClass)); } /** diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/IFunction.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/IFunction.java index ec45095dd..cce562f37 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/IFunction.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/IFunction.java @@ -39,6 +39,7 @@ import java.util.List; import java.util.Objects; import java.util.Set; +import java.util.stream.Collectors; import javax.xml.namespace.QName; @@ -91,7 +92,9 @@ enum FunctionProperty { * @return the function's name */ @NonNull - String getName(); + default String getName() { + return ObjectUtils.notNull(getQName().getLocalPart()); + } /** * Retrieve the namespace of the function. @@ -99,7 +102,9 @@ enum FunctionProperty { * @return the function's namespace */ @NonNull - String getNamespace(); + default String getNamespace() { + return ObjectUtils.notNull(getQName().getNamespaceURI()); + } /** * Retrieve the namespace qualified name of the function. @@ -107,9 +112,7 @@ enum FunctionProperty { * @return the namespace qualified name */ @NonNull - default QName getQName() { - return new QName(getNamespace(), getName()); - } + QName getQName(); /** * Retrieve the set of assigned function properties. @@ -223,7 +226,16 @@ ISequence execute( * * @return the signature */ - String toSignature(); + @NonNull + default String toSignature() { + return ObjectUtils.notNull(String.format("Q{%s}%s(%s) as %s", + getNamespace(), + getName(), + getArguments().isEmpty() ? "" + : getArguments().stream().map(IArgument::toSignature).collect(Collectors.joining(",")) + + (isArityUnbounded() ? ", ..." : ""), + getResult().toSignature())); + } /** * Construct a new function signature builder. diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/IFunctionLibrary.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/IFunctionLibrary.java index 393e9c36f..12616701a 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/IFunctionLibrary.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/IFunctionLibrary.java @@ -40,7 +40,7 @@ public interface IFunctionLibrary { * @return a stream of function signatures */ @NonNull - Stream getFunctionsAsStream(); + Stream stream(); /** * Determine if there is a function with the provided name that supports the diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/ISequenceType.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/ISequenceType.java index dbb26a80e..8c54d5765 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/ISequenceType.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/ISequenceType.java @@ -54,6 +54,11 @@ public String toSignature() { } }; + @NonNull + static ISequenceType of(@NonNull Class type, @NonNull Occurrence occurrence) { + return new SequenceTypeImpl(type, occurrence); + } + /** * Determine if the sequence is empty (if it holds any data) or not. * @@ -81,5 +86,6 @@ public String toSignature() { * * @return the signature */ + @NonNull String toSignature(); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/InvalidArgumentFunctionException.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/InvalidArgumentFunctionException.java index b3504b28a..37b62a3b7 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/InvalidArgumentFunctionException.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/InvalidArgumentFunctionException.java @@ -103,7 +103,7 @@ public InvalidArgumentFunctionException(int code, Throwable cause) { } @Override - protected String getCodePrefix() { + public String getCodePrefix() { return "FORG"; } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/InvalidTypeFunctionException.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/InvalidTypeFunctionException.java index 9fe744ca9..05b78569a 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/InvalidTypeFunctionException.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/InvalidTypeFunctionException.java @@ -95,7 +95,7 @@ private static String generateMessage(@NonNull IItem item) { } @Override - protected String getCodePrefix() { + public String getCodePrefix() { return "FOTY"; } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/InvalidValueForCastFunctionException.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/InvalidValueForCastFunctionException.java index 0750128fc..183640e9b 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/InvalidValueForCastFunctionException.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/InvalidValueForCastFunctionException.java @@ -41,7 +41,7 @@ public class InvalidValueForCastFunctionException * the exception message */ public InvalidValueForCastFunctionException(String message) { - super(InvalidArgumentFunctionException.INVALID_VALUE_FOR_CAST, message); + super(INVALID_VALUE_FOR_CAST, message); } /** @@ -54,7 +54,7 @@ public InvalidValueForCastFunctionException(String message) { * the original exception cause */ public InvalidValueForCastFunctionException(String message, Throwable cause) { - super(InvalidArgumentFunctionException.INVALID_VALUE_FOR_CAST, message, cause); + super(INVALID_VALUE_FOR_CAST, message, cause); } /** @@ -64,7 +64,7 @@ public InvalidValueForCastFunctionException(String message, Throwable cause) { * the original exception cause */ public InvalidValueForCastFunctionException(Throwable cause) { - super(InvalidArgumentFunctionException.INVALID_VALUE_FOR_CAST, cause); + super(INVALID_VALUE_FOR_CAST, cause); } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/JsonFunctionException.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/JsonFunctionException.java new file mode 100644 index 000000000..78af9739b --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/JsonFunctionException.java @@ -0,0 +1,98 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.function; + +import gov.nist.secauto.metaschema.core.metapath.AbstractCodedMetapathException; + +public class JsonFunctionException + extends AbstractCodedMetapathException { + /** + * err:FOJS0003: + * This error is raised if the input contains duplicate keys, when the chosen + * policy is to reject duplicates. + */ + public static final int DUPLICATE_KEYS = 3; + + /** + * err:FOJS0005: + * This error is raised if the $options map contains an invalid entry. + */ + public static final int INVALID_OPTION = 5; + + /** + * the serial version UID. + */ + private static final long serialVersionUID = 1L; + + /** + * Constructs a new exception with the provided {@code code}, {@code message}, + * and no cause. + * + * @param code + * the error code value + * @param message + * the exception message + */ + public JsonFunctionException(int code, String message) { + super(code, message); + } + + /** + * Constructs a new exception with the provided {@code code}, {@code message}, + * and {@code cause}. + * + * @param code + * the error code value + * @param message + * the exception message + * @param cause + * the original exception cause + */ + public JsonFunctionException(int code, String message, Throwable cause) { + super(code, message, cause); + } + + /** + * Constructs a new exception with the provided {@code code}, no message, and + * the {@code cause}. + * + * @param code + * the error code value + * @param cause + * the original exception cause + */ + public JsonFunctionException(int code, Throwable cause) { + super(code, cause); + } + + @Override + public String getCodePrefix() { + return "FOJS"; + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/SequenceTypeImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/SequenceTypeImpl.java index 2db8d2ce8..ece58474a 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/SequenceTypeImpl.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/SequenceTypeImpl.java @@ -27,14 +27,17 @@ package gov.nist.secauto.metaschema.core.metapath.function; import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.metapath.item.TypeSystem; import java.util.Objects; +import edu.umd.cs.findbugs.annotations.NonNull; + class SequenceTypeImpl implements ISequenceType { private final Class type; private final Occurrence occurrence; - public SequenceTypeImpl(Class type, Occurrence occurrence) { + public SequenceTypeImpl(@NonNull Class type, @NonNull Occurrence occurrence) { Objects.requireNonNull(type, "type"); Objects.requireNonNull(occurrence, "occurrence"); this.type = type; @@ -65,8 +68,11 @@ public String toString() { public String toSignature() { StringBuilder builder = new StringBuilder(); + Class type = getType(); // name - builder.append(getType().getName()) + builder.append(type == null + ? "" + : TypeSystem.getName(type)) // occurrence .append(getOccurrence().getIndicator()); diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/UriFunctionException.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/UriFunctionException.java index f30461b7e..d5b3d9a64 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/UriFunctionException.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/UriFunctionException.java @@ -98,7 +98,7 @@ public UriFunctionException(int code, Throwable cause) { } @Override - protected String getCodePrefix() { + public String getCodePrefix() { return "FONS"; } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayAppend.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayAppend.java new file mode 100644 index 000000000..c3ac3a69c --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayAppend.java @@ -0,0 +1,107 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.function.library; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ICollectionValue; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.MetapathConstants; +import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils; +import gov.nist.secauto.metaschema.core.metapath.function.IArgument; +import gov.nist.secauto.metaschema.core.metapath.function.IFunction; +import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.IArrayItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.ArrayList; +import java.util.List; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public final class ArrayAppend { + @NonNull + public static final IFunction SIGNATURE = IFunction.builder() + .name("append") + .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS_ARRAY) + .deterministic() + .contextIndependent() + .focusIndependent() + .argument(IArgument.builder() + .name("array") + .type(IArrayItem.class) + .one() + .build()) + .argument(IArgument.builder() + .name("appendage") + .type(IItem.class) + .zeroOrMore() + .build()) + .returnType(IArrayItem.class) + .returnOne() + .functionHandler(ArrayAppend::execute) + .build(); + + private ArrayAppend() { + // disable construction + } + + @SuppressWarnings("unused") + @NonNull + private static ISequence> execute(@NonNull IFunction function, + @NonNull List> arguments, + @NonNull DynamicContext dynamicContext, + IItem focus) { + IArrayItem array = FunctionUtils.asType(ObjectUtils.requireNonNull( + arguments.get(0).getFirstItem(true))); + @SuppressWarnings("unchecked") T appendage = (T) arguments.get(1).toCollectionValue(); + + return ISequence.of(append(array, appendage)); + } + + /** + * An implementation of XPath 3.1 array:append. + * + * @param + * the type of items in the given Metapath array + * @param array + * the target Metapath array + * @param appendage + * the Metapath item to append to the identified array + * @return a new array containing the modification + */ + @NonNull + public static IArrayItem append( + @NonNull IArrayItem array, + @NonNull T appendage) { + + List copy = new ArrayList<>(array); + copy.add(appendage); + + return IArrayItem.ofCollection(copy); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayFlatten.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayFlatten.java new file mode 100644 index 000000000..ca0059262 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayFlatten.java @@ -0,0 +1,102 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.function.library; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.MetapathConstants; +import gov.nist.secauto.metaschema.core.metapath.function.IArgument; +import gov.nist.secauto.metaschema.core.metapath.function.IFunction; +import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.IArrayItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.List; +import java.util.stream.Stream; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public final class ArrayFlatten { + @NonNull + static final IFunction SIGNATURE = IFunction.builder() + .name("flatten") + .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS_ARRAY) + .deterministic() + .contextIndependent() + .focusIndependent() + .argument(IArgument.builder() + .name("input") + .type(IItem.class) + .zeroOrMore() + .build()) + .returnType(IItem.class) + .returnZeroOrMore() + .functionHandler(ArrayFlatten::execute) + .build(); + + private ArrayFlatten() { + // disable construction + } + + @SuppressWarnings("unused") + @NonNull + private static ISequence execute(@NonNull IFunction function, + @NonNull List> arguments, + @NonNull DynamicContext dynamicContext, + IItem focus) { + ISequence input = ObjectUtils.requireNonNull(arguments.get(0)); + + return ISequence.of(flatten(input)); + } + + /** + * An implementation of XPath 3.1 array:flatten. + * + * @param input + * the items to flatten + * @return the flattened items + */ + @SuppressWarnings("null") + @NonNull + public static Stream flatten(@NonNull List input) { + return input.stream() + .flatMap(ArrayFlatten::flatten); + } + + @SuppressWarnings("null") + @NonNull + public static Stream flatten(@NonNull IItem item) { + return item instanceof IArrayItem + // flatten the array members + ? ((IArrayItem) item).stream() + .flatMap(member -> member.asSequence().stream() + .flatMap(ArrayFlatten::flatten)) + // use the item + : ObjectUtils.notNull(Stream.of(item)); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayGet.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayGet.java new file mode 100644 index 000000000..8aa5d49be --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayGet.java @@ -0,0 +1,121 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.function.library; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ICollectionValue; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.MetapathConstants; +import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils; +import gov.nist.secauto.metaschema.core.metapath.function.IArgument; +import gov.nist.secauto.metaschema.core.metapath.function.IFunction; +import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.metapath.item.atomic.IIntegerItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.ArrayException; +import gov.nist.secauto.metaschema.core.metapath.item.function.IArrayItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.List; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public final class ArrayGet { + @NonNull + public static final IFunction SIGNATURE = IFunction.builder() + .name("get") + .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS_ARRAY) + .deterministic() + .contextIndependent() + .focusIndependent() + .argument(IArgument.builder() + .name("array") + .type(IArrayItem.class) + .one() + .build()) + .argument(IArgument.builder() + .name("position") + .type(IIntegerItem.class) + .one() + .build()) + .returnType(IItem.class) + .returnZeroOrOne() + .functionHandler(ArrayGet::execute) + .build(); + + private ArrayGet() { + // disable construction + } + + @SuppressWarnings("unused") + @NonNull + private static ISequence execute(@NonNull IFunction function, + @NonNull List> arguments, + @NonNull DynamicContext dynamicContext, + IItem focus) { + IArrayItem array = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0).getFirstItem(true))); + IIntegerItem position = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(1).getFirstItem(true))); + + return get(array, position).asSequence(); + } + + /** + * An implementation of XPath 3.1 array:get. + * + * @param + * the type of items in the given Metapath array + * @param target + * the array of Metapath items that is the target of retrieval + * @param positionItem + * the integer position of the item to retrieve + * @return the retrieved item + * @throws ArrayException + * if the position is not in the range of 1 to array:size + */ + @NonNull + public static T get( + @NonNull List target, + @NonNull IIntegerItem positionItem) { + return get(target, positionItem.asInteger().intValue()); + } + + @NonNull + public static T get( + @NonNull List target, + int position) { + try { + return ObjectUtils.requireNonNull(target.get(position - 1)); + } catch (IndexOutOfBoundsException ex) { + throw new ArrayException( + ArrayException.INDEX_OUT_OF_BOUNDS, + String.format("The index %d is outside the range of values for the array size '%d'.", + position, + target.size()), + ex); + } + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayHead.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayHead.java new file mode 100644 index 000000000..ac5f1d285 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayHead.java @@ -0,0 +1,93 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.function.library; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ICollectionValue; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.MetapathConstants; +import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils; +import gov.nist.secauto.metaschema.core.metapath.function.IArgument; +import gov.nist.secauto.metaschema.core.metapath.function.IFunction; +import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.IArrayItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.List; + +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; + +public final class ArrayHead { + @NonNull + static final IFunction SIGNATURE = IFunction.builder() + .name("head") + .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS_ARRAY) + .deterministic() + .contextIndependent() + .focusIndependent() + .argument(IArgument.builder() + .name("array") + .type(IArrayItem.class) + .one() + .build()) + .returnType(IItem.class) + .returnZeroOrOne() + .functionHandler(ArrayHead::execute) + .build(); + + private ArrayHead() { + // disable construction + } + + @SuppressWarnings("unused") + @NonNull + private static ISequence execute(@NonNull IFunction function, + @NonNull List> arguments, + @NonNull DynamicContext dynamicContext, + IItem focus) { + IArrayItem array = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0).getFirstItem(true))); + + ICollectionValue result = head(array); + return result == null ? ISequence.empty() : result.asSequence(); + } + + /** + * An implementation of XPath 3.1 array:head. + * + * @param + * the type of items in the given Metapath array + * @param array + * the array to get the head item from + * @return the head item + */ + @Nullable + public static T head(@NonNull IArrayItem array) { + return array.isEmpty() ? null : array.get(0); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayInsertBefore.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayInsertBefore.java new file mode 100644 index 000000000..3d7807396 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayInsertBefore.java @@ -0,0 +1,124 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.function.library; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ICollectionValue; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.MetapathConstants; +import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils; +import gov.nist.secauto.metaschema.core.metapath.function.IArgument; +import gov.nist.secauto.metaschema.core.metapath.function.IFunction; +import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.metapath.item.atomic.IIntegerItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.ArrayException; +import gov.nist.secauto.metaschema.core.metapath.item.function.IArrayItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.List; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public final class ArrayInsertBefore { + @NonNull + public static final IFunction SIGNATURE = IFunction.builder() + .name("insert-before") + .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS_ARRAY) + .deterministic() + .contextIndependent() + .focusIndependent() + .argument(IArgument.builder() + .name("array") + .type(IArrayItem.class) + .one() + .build()) + .argument(IArgument.builder() + .name("position") + .type(IIntegerItem.class) + .one() + .build()) + .argument(IArgument.builder() + .name("member") + .type(IItem.class) + .zeroOrMore() + .build()) + .returnType(IArrayItem.class) + .returnOne() + .functionHandler(ArrayInsertBefore::execute) + .build(); + + private ArrayInsertBefore() { + // disable construction + } + + @SuppressWarnings("unused") + @NonNull + private static ISequence> execute(@NonNull IFunction function, + @NonNull List> arguments, + @NonNull DynamicContext dynamicContext, + IItem focus) { + IArrayItem array = FunctionUtils.asType(ObjectUtils.requireNonNull( + arguments.get(0).getFirstItem(true))); + IIntegerItem position = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(1).getFirstItem(true))); + @SuppressWarnings("unchecked") T member = (T) ObjectUtils.requireNonNull(arguments.get(2)).toCollectionValue(); + + return ISequence.of(insertBefore(array, position, member)); + } + + /** + * An implementation of XPath 3.1 array:insert-before. + * + * @param + * the type of items in the given Metapath array + * @param array + * the target Metapath array + * @param positionItem + * the integer position of the item to insert before + * @param member + * the Metapath item to insert into the identified array + * @return a new array containing the modification + * @throws ArrayException + * if the position is not in the range of 1 to array:size + */ + @NonNull + public static IArrayItem insertBefore( + @NonNull IArrayItem array, + @NonNull IIntegerItem positionItem, + @NonNull T member) { + return insertBefore(array, positionItem.asInteger().intValueExact(), member); + } + + @NonNull + public static IArrayItem insertBefore(@NonNull IArrayItem array, int position, + @NonNull T member) { + return ArrayJoin.join(ObjectUtils.notNull(List.of( + ArraySubarray.subarray(array, 1, position - 1), + IArrayItem.of(member), + ArraySubarray.subarray(array, position)))); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayJoin.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayJoin.java new file mode 100644 index 000000000..d8d7aa7a3 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayJoin.java @@ -0,0 +1,96 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.function.library; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ICollectionValue; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.MetapathConstants; +import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils; +import gov.nist.secauto.metaschema.core.metapath.function.IArgument; +import gov.nist.secauto.metaschema.core.metapath.function.IFunction; +import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.IArrayItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public final class ArrayJoin { + @NonNull + public static final IFunction SIGNATURE = IFunction.builder() + .name("join") + .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS_ARRAY) + .deterministic() + .contextIndependent() + .focusIndependent() + .argument(IArgument.builder() + .name("array") + .type(IArrayItem.class) + .zeroOrMore() + .build()) + .returnType(IItem.class) + .returnZeroOrOne() + .functionHandler(ArrayJoin::execute) + .build(); + + private ArrayJoin() { + // disable construction + } + + @SuppressWarnings("unused") + @NonNull + private static ISequence> execute(@NonNull IFunction function, + @NonNull List> arguments, + @NonNull DynamicContext dynamicContext, + IItem focus) { + ISequence> arrays = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0))); + + return join(arrays).asSequence(); + } + + /** + * An implementation of XPath 3.1 array:join. + * + * @param + * the type of items in the given Metapath array + * @param arrays + * the arrays to join + * @return a new combined array + */ + @NonNull + public static IArrayItem join( + @NonNull Collection> arrays) { + return IArrayItem.ofCollection(ObjectUtils.notNull(arrays.stream() + .flatMap(Collection::stream) + .collect(Collectors.toList()))); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayPut.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayPut.java new file mode 100644 index 000000000..e84f7cc93 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayPut.java @@ -0,0 +1,134 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.function.library; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ICollectionValue; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.MetapathConstants; +import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils; +import gov.nist.secauto.metaschema.core.metapath.function.IArgument; +import gov.nist.secauto.metaschema.core.metapath.function.IFunction; +import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.metapath.item.atomic.IIntegerItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.ArrayException; +import gov.nist.secauto.metaschema.core.metapath.item.function.IArrayItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.ArrayList; +import java.util.List; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public final class ArrayPut { + @NonNull + public static final IFunction SIGNATURE = IFunction.builder() + .name("put") + .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS_ARRAY) + .deterministic() + .contextIndependent() + .focusIndependent() + .argument(IArgument.builder() + .name("array") + .type(IArrayItem.class) + .one() + .build()) + .argument(IArgument.builder() + .name("position") + .type(IIntegerItem.class) + .one() + .build()) + .argument(IArgument.builder() + .name("member") + .type(IItem.class) + .zeroOrMore() + .build()) + .returnType(IArrayItem.class) + .returnOne() + .functionHandler(ArrayPut::execute) + .build(); + + private ArrayPut() { + // disable construction + } + + @SuppressWarnings("unused") + @NonNull + private static ISequence> execute(@NonNull IFunction function, + @NonNull List> arguments, + @NonNull DynamicContext dynamicContext, + IItem focus) { + IArrayItem array = FunctionUtils.asType(ObjectUtils.requireNonNull( + arguments.get(0).getFirstItem(true))); + IIntegerItem position = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(1).getFirstItem(true))); + @SuppressWarnings("unchecked") T member = (T) arguments.get(2).toCollectionValue(); + + return put(array, position, member).asSequence(); + } + + /** + * An implementation of XPath 3.1 array:put. + * + * @param + * the type of items in the given Metapath array + * @param array + * the target Metapath array + * @param positionItem + * the integer position of the item to replace + * @param member + * the Metapath item to replace the identified array member with + * @return a new array containing the modification + * @throws ArrayException + * if the position is not in the range of 1 to array:size + */ + @NonNull + public static IArrayItem put( + @NonNull IArrayItem array, + @NonNull IIntegerItem positionItem, + @NonNull T member) { + return put(array, positionItem.asInteger().intValueExact(), member); + } + + @NonNull + public static IArrayItem put(@NonNull IArrayItem array, int position, + @NonNull T member) { + List copy = new ArrayList<>(array); + try { + copy.set(position - 1, member); + } catch (IndexOutOfBoundsException ex) { + throw new ArrayException( + ArrayException.INDEX_OUT_OF_BOUNDS, + String.format("The position %d is outside the range of values for the array of size '%d'.", + position, + copy.size()), + ex); + } + + return IArrayItem.ofCollection(copy); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayRemove.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayRemove.java new file mode 100644 index 000000000..64a1a2019 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayRemove.java @@ -0,0 +1,128 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.function.library; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.MetapathConstants; +import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils; +import gov.nist.secauto.metaschema.core.metapath.function.IArgument; +import gov.nist.secauto.metaschema.core.metapath.function.IFunction; +import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.metapath.item.atomic.IIntegerItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.ArrayException; +import gov.nist.secauto.metaschema.core.metapath.item.function.IArrayItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public final class ArrayRemove { + @NonNull + public static final IFunction SIGNATURE = IFunction.builder() + .name("remove") + .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS_ARRAY) + .deterministic() + .contextIndependent() + .focusIndependent() + .argument(IArgument.builder() + .name("array") + .type(IArrayItem.class) + .one() + .build()) + .argument(IArgument.builder() + .name("positions") + .type(IIntegerItem.class) + .zeroOrMore() + .build()) + .returnType(IArrayItem.class) + .returnOne() + .functionHandler(ArrayRemove::execute) + .build(); + + private ArrayRemove() { + // disable construction + } + + @SuppressWarnings("unused") + @NonNull + private static ISequence> execute(@NonNull IFunction function, + @NonNull List> arguments, + @NonNull DynamicContext dynamicContext, + IItem focus) { + IArrayItem array = FunctionUtils.asType(ObjectUtils.requireNonNull( + arguments.get(0).getFirstItem(true))); + ISequence positions = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(1))); + + return ISequence.of(removeItems(array, positions)); + } + + /** + * An implementation of XPath 3.1 array:remove. + * + * @param + * the type of items in the given Metapath array + * @param array + * the target Metapath array + * @param positions + * the integer position of the items to remove + * @return a new array containing the modification + * @throws ArrayException + * if the position is not in the range of 1 to array:size + */ + @NonNull + public static IArrayItem removeItems( + @NonNull IArrayItem array, + @NonNull Collection positions) { + return remove( + array, + ObjectUtils.notNull(positions.stream() + .map(position -> position.asInteger().intValueExact()) + .collect(Collectors.toSet()))); + } + + @NonNull + public static IArrayItem remove( + @NonNull IArrayItem array, + @NonNull Collection positions) { + Set positionSet = positions instanceof Set ? (Set) positions : new HashSet<>(positions); + + List remaining = ObjectUtils.notNull(IntStream.range(1, array.size() + 1) + .filter(index -> !positionSet.contains(index)) + .mapToObj(index -> array.get(index - 1)) + .collect(Collectors.toList())); + + return IArrayItem.ofCollection(remaining); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayReverse.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayReverse.java new file mode 100644 index 000000000..fba9e9ca7 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayReverse.java @@ -0,0 +1,97 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.function.library; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ICollectionValue; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.MetapathConstants; +import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils; +import gov.nist.secauto.metaschema.core.metapath.function.IArgument; +import gov.nist.secauto.metaschema.core.metapath.function.IFunction; +import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.IArrayItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public final class ArrayReverse { + @NonNull + public static final IFunction SIGNATURE = IFunction.builder() + .name("reverse") + .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS_ARRAY) + .deterministic() + .contextIndependent() + .focusIndependent() + .argument(IArgument.builder() + .name("array") + .type(IArrayItem.class) + .one() + .build()) + .returnType(IArrayItem.class) + .returnOne() + .functionHandler(ArrayReverse::execute) + .build(); + + private ArrayReverse() { + // disable construction + } + + @SuppressWarnings("unused") + @NonNull + private static ISequence> execute(@NonNull IFunction function, + @NonNull List> arguments, + @NonNull DynamicContext dynamicContext, + IItem focus) { + IArrayItem array = FunctionUtils.asType(ObjectUtils.requireNonNull( + arguments.get(0).getFirstItem(true))); + + return ISequence.of(reverse(array)); + } + + /** + * An implementation of XPath 3.1 array:reverse. + * + * @param + * the type of items in the given Metapath array + * @param array + * the target Metapath array + * @return a new array containing the modification + */ + @NonNull + public static IArrayItem reverse( + @NonNull IArrayItem array) { + List copy = new ArrayList<>(array); + Collections.reverse(copy); + return IArrayItem.ofCollection(copy); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArraySize.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArraySize.java new file mode 100644 index 000000000..26370a45c --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArraySize.java @@ -0,0 +1,80 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.function.library; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.MetapathConstants; +import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils; +import gov.nist.secauto.metaschema.core.metapath.function.IArgument; +import gov.nist.secauto.metaschema.core.metapath.function.IFunction; +import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.metapath.item.atomic.IIntegerItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.IArrayItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.List; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class ArraySize { + @NonNull + static final IFunction SIGNATURE = IFunction.builder() + .name("size") + .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS_ARRAY) + .deterministic() + .contextIndependent() + .focusIndependent() + .argument(IArgument.builder() + .name("array") + .type(IArrayItem.class) + .one() + .build()) + .returnType(IIntegerItem.class) + .returnOne() + .functionHandler(ArraySize::execute) + .build(); + + /** + * An implementation of XPath 3.1 array:size. + * + * @param array + * the arrays to join + * @return a new combined array + */ + @SuppressWarnings("unused") + @NonNull + private static ISequence execute(@NonNull IFunction function, + @NonNull List> arguments, + @NonNull DynamicContext dynamicContext, + IItem focus) { + IArrayItem array = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0).getFirstItem(true))); + + return ISequence.of(IIntegerItem.valueOf(array.size())); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArraySubarray.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArraySubarray.java new file mode 100644 index 000000000..f0a4ab406 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArraySubarray.java @@ -0,0 +1,204 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.function.library; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ICollectionValue; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.MetapathConstants; +import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils; +import gov.nist.secauto.metaschema.core.metapath.function.IArgument; +import gov.nist.secauto.metaschema.core.metapath.function.IFunction; +import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.metapath.item.atomic.IIntegerItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.ArrayException; +import gov.nist.secauto.metaschema.core.metapath.item.function.IArrayItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.ArrayList; +import java.util.List; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public final class ArraySubarray { + @NonNull + public static final IFunction SIGNATURE_TWO_ARG = IFunction.builder() + .name("subarray") + .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS_ARRAY) + .deterministic() + .contextIndependent() + .focusIndependent() + .argument(IArgument.builder() + .name("array") + .type(IArrayItem.class) + .one() + .build()) + .argument(IArgument.builder() + .name("start") + .type(IIntegerItem.class) + .one() + .build()) + .returnType(IArrayItem.class) + .returnOne() + .functionHandler(ArraySubarray::executeTwoArg) + .build(); + @NonNull + public static final IFunction SIGNATURE_THREE_ARG = IFunction.builder() + .name("subarray") + .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS_ARRAY) + .deterministic() + .contextIndependent() + .focusIndependent() + .argument(IArgument.builder() + .name("array") + .type(IArrayItem.class) + .one() + .build()) + .argument(IArgument.builder() + .name("start") + .type(IIntegerItem.class) + .one() + .build()) + .argument(IArgument.builder() + .name("length") + .type(IIntegerItem.class) + .one() + .build()) + .returnType(IArrayItem.class) + .returnOne() + .functionHandler(ArraySubarray::executeThreeArg) + .build(); + + private ArraySubarray() { + // disable construction + } + + @SuppressWarnings("unused") + @NonNull + private static ISequence> executeTwoArg(@NonNull IFunction function, + @NonNull List> arguments, + @NonNull DynamicContext dynamicContext, + IItem focus) { + IArrayItem array = FunctionUtils.asType(ObjectUtils.requireNonNull( + arguments.get(0).getFirstItem(true))); + IIntegerItem start = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(1).getFirstItem(true))); + + return ISequence.of(subarray(array, start)); + } + + @SuppressWarnings("unused") + @NonNull + private static ISequence> executeThreeArg(@NonNull IFunction function, + @NonNull List> arguments, + @NonNull DynamicContext dynamicContext, + IItem focus) { + IArrayItem array = FunctionUtils.asType(ObjectUtils.requireNonNull( + arguments.get(0).getFirstItem(true))); + IIntegerItem start = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(1).getFirstItem(true))); + IIntegerItem length = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(2).getFirstItem(true))); + + return ISequence.of(subarray(array, start, length)); + } + + /** + * An implementation of XPath 3.1 array:subarray. + * + * @param + * the type of items in the given Metapath array + * @param array + * the target Metapath array + * @param startItem + * the integer position of the item to start with (inclusive) + * @return a new array consisting of the items in the identified range + * @throws ArrayException + * if the position is not in the range of 1 to array:size + */ + @SuppressWarnings("PMD.OnlyOneReturn") + @NonNull + public static IArrayItem subarray( + @NonNull IArrayItem array, + @NonNull IIntegerItem startItem) { + return subarray(array, startItem.asInteger().intValueExact()); + } + + /** + * An implementation of XPath 3.1 array:subarray. + * + * @param + * the type of items in the given Metapath array + * @param array + * the target Metapath array + * @param startItem + * the integer position of the item to start with (inclusive) + * @param lengthItem + * the integer count of items to include starting with the item at the + * start position + * @return a new array consisting of the items in the identified range + * @throws ArrayException + * if the length is negative or the position is not in the range of 1 + * to array:size + */ + @SuppressWarnings("PMD.OnlyOneReturn") + @NonNull + public static IArrayItem subarray( + @NonNull IArrayItem array, + @NonNull IIntegerItem startItem, + @NonNull IIntegerItem lengthItem) { + return subarray(array, startItem.asInteger().intValueExact(), lengthItem.asInteger().intValueExact()); + } + + @NonNull + public static IArrayItem subarray(@NonNull IArrayItem array, int start) { + return subarray(array, start, array.size() - start + 1); + } + + @NonNull + public static IArrayItem subarray(@NonNull IArrayItem array, int start, + int length) { + if (length < 0) { + throw new ArrayException( + ArrayException.NEGATIVE_ARRAY_LENGTH, String.format("The length '%d' is negative.", length)); + } + + List copy; + try { + copy = array.subList(start - 1, start - 1 + length); + } catch (IndexOutOfBoundsException ex) { + throw new ArrayException( + ArrayException.INDEX_OUT_OF_BOUNDS, + String.format("The start + length (%d + %d) exceeds the array length '%d'.", + start, + length, + array.size()), + ex); + } + + return IArrayItem.ofCollection(new ArrayList<>(copy)); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayTail.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayTail.java new file mode 100644 index 000000000..d45ed09df --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayTail.java @@ -0,0 +1,91 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.function.library; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.MetapathConstants; +import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils; +import gov.nist.secauto.metaschema.core.metapath.function.IArgument; +import gov.nist.secauto.metaschema.core.metapath.function.IFunction; +import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.IArrayItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.List; + +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; + +public final class ArrayTail { + @NonNull + static final IFunction SIGNATURE = IFunction.builder() + .name("tail") + .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS_ARRAY) + .deterministic() + .contextIndependent() + .focusIndependent() + .argument(IArgument.builder() + .name("array") + .type(IArrayItem.class) + .one() + .build()) + .returnType(IItem.class) + .returnZeroOrOne() + .functionHandler(ArrayTail::execute) + .build(); + + private ArrayTail() { + // disable construction + } + + @SuppressWarnings("unused") + @NonNull + private static ISequence> execute(@NonNull IFunction function, + @NonNull List> arguments, + @NonNull DynamicContext dynamicContext, + IItem focus) { + IArrayItem array = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0).getFirstItem(true))); + + return ISequence.of(tail(array)); + } + + /** + * An implementation of XPath 3.1 array:tail. + * + * @param + * the type of items in the given Metapath array + * @param array + * the array to get the tail items from + * @return the tail items + */ + @Nullable + public static IArrayItem tail(@NonNull IArrayItem array) { + return ArraySubarray.subarray(array, 2); + } +} 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 f6c45a1c8..7a08f52fb 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 @@ -75,6 +75,9 @@ static IFunction signature( return IFunction.builder() .name(name) .namespace(namespace) + .deterministic() + .contextIndependent() + .focusIndependent() .argument(IArgument.builder() .name("arg1") .type(IAnyAtomicItem.class) @@ -105,7 +108,7 @@ public ISequence execute(@NonNull IFunction function, ISequence arg = FunctionUtils.asType( ObjectUtils.notNull(arguments.get(0))); - IAnyAtomicItem item = FunctionUtils.getFirstItem(arg, true); + IAnyAtomicItem item = arg.getFirstItem(true); if (item == null) { return ISequence.empty(); // NOPMD - readability } 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 21fd664bc..2b40c53a2 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 @@ -132,6 +132,7 @@ public DefaultFunctionLibrary() { // NOPMD - intentional // https://www.w3.org/TR/xpath-functions-31/#func-month-from-date // https://www.w3.org/TR/xpath-functions-31/#func-month-from-dateTime // https://www.w3.org/TR/xpath-functions-31/#func-months-from-duration + // https://www.w3.org/TR/xpath-functions-31/#func-node-name // https://www.w3.org/TR/xpath-functions-31/#func-normalize-space // https://www.w3.org/TR/xpath-functions-31/#func-normalize-unicode // https://www.w3.org/TR/xpath-functions-31/#func-not @@ -164,6 +165,7 @@ public DefaultFunctionLibrary() { // NOPMD - intentional registerFunction(FnStartsWith.SIGNATURE); // https://www.w3.org/TR/xpath-functions-31/#func-static-base-uri registerFunction(FnStaticBaseUri.SIGNATURE); + // P0: https://www.w3.org/TR/xpath-functions-31/#func-string // P1: https://www.w3.org/TR/xpath-functions-31/#func-string-join // P1: https://www.w3.org/TR/xpath-functions-31/#func-string-length // P1: https://www.w3.org/TR/xpath-functions-31/#func-subsequence @@ -191,29 +193,91 @@ public DefaultFunctionLibrary() { // NOPMD - intentional // https://www.w3.org/TR/xpath-functions-31/#func-years-from-duration // P2: https://www.w3.org/TR/xpath-functions-31/#func-zero-or-one - // xpath casting functions - registerFunction( - CastFunction.signature(MetapathConstants.NS_XML_SCHEMA, "boolean", IBooleanItem.class, IBooleanItem::cast)); - registerFunction(CastFunction.signature( - MetapathConstants.NS_XML_SCHEMA, "date", IDateItem.class, IDateItem::cast)); - registerFunction(CastFunction.signature( - MetapathConstants.NS_XML_SCHEMA, "dateTime", IDateTimeItem.class, IDateTimeItem::cast)); - registerFunction(CastFunction.signature( - MetapathConstants.NS_XML_SCHEMA, "decimal", IDecimalItem.class, IDecimalItem::cast)); - registerFunction(CastFunction.signature( - MetapathConstants.NS_XML_SCHEMA, "duration", IDurationItem.class, IDurationItem::cast)); - registerFunction(CastFunction.signature( - MetapathConstants.NS_XML_SCHEMA, "integer", IIntegerItem.class, IIntegerItem::cast)); - registerFunction(CastFunction.signature( - MetapathConstants.NS_XML_SCHEMA, "NCName", INcNameItem.class, INcNameItem::cast)); - registerFunction(CastFunction.signature( - MetapathConstants.NS_XML_SCHEMA, "nonNegativeInteger", INonNegativeIntegerItem.class, - INonNegativeIntegerItem::cast)); - registerFunction(CastFunction.signature( - MetapathConstants.NS_XML_SCHEMA, "positiveInteger", IPositiveIntegerItem.class, - IPositiveIntegerItem::cast)); - registerFunction(CastFunction.signature( - MetapathConstants.NS_XML_SCHEMA, "string", IStringItem.class, IStringItem::cast)); + // https://www.w3.org/TR/xpath-functions-31/#func-array-get + registerFunction(ArrayGet.SIGNATURE); + // https://www.w3.org/TR/xpath-functions-31/#func-array-size + registerFunction(ArraySize.SIGNATURE); + // https://www.w3.org/TR/xpath-functions-31/#func-array-put + registerFunction(ArrayPut.SIGNATURE); + // https://www.w3.org/TR/xpath-functions-31/#func-array-append + registerFunction(ArrayAppend.SIGNATURE); + // https://www.w3.org/TR/xpath-functions-31/#func-array-subarray + registerFunction(ArraySubarray.SIGNATURE_TWO_ARG); + registerFunction(ArraySubarray.SIGNATURE_THREE_ARG); + // https://www.w3.org/TR/xpath-functions-31/#func-array-remove + registerFunction(ArrayRemove.SIGNATURE); + // https://www.w3.org/TR/xpath-functions-31/#func-array-insert-before + registerFunction(ArrayInsertBefore.SIGNATURE); + // https://www.w3.org/TR/xpath-functions-31/#func-array-head + registerFunction(ArrayHead.SIGNATURE); + // https://www.w3.org/TR/xpath-functions-31/#func-array-tail + registerFunction(ArrayTail.SIGNATURE); + // https://www.w3.org/TR/xpath-functions-31/#func-array-reverse + registerFunction(ArrayReverse.SIGNATURE); + // https://www.w3.org/TR/xpath-functions-31/#func-array-join + registerFunction(ArrayJoin.SIGNATURE); + // P3: https://www.w3.org/TR/xpath-functions-31/#func-array-for-each + // P3: https://www.w3.org/TR/xpath-functions-31/#func-array-filter + // P3: https://www.w3.org/TR/xpath-functions-31/#func-array-fold-left + // P3: https://www.w3.org/TR/xpath-functions-31/#func-array-fold-right + // P3: https://www.w3.org/TR/xpath-functions-31/#func-array-for-each-pair + // P3: https://www.w3.org/TR/xpath-functions-31/#func-array-sort + // https://www.w3.org/TR/xpath-functions-31/#func-array-flatten + registerFunction(ArrayFlatten.SIGNATURE); + + // https://www.w3.org/TR/xpath-functions-31/#func-map-merge + registerFunction(MapMerge.SIGNATURE_ONE_ARG); + registerFunction(MapMerge.SIGNATURE_TWO_ARG); + // https://www.w3.org/TR/xpath-functions-31/#func-map-size + registerFunction(MapSize.SIGNATURE); + // https://www.w3.org/TR/xpath-functions-31/#func-map-keys + registerFunction(MapKeys.SIGNATURE); + // https://www.w3.org/TR/xpath-functions-31/#func-map-contains + registerFunction(MapContains.SIGNATURE); + // https://www.w3.org/TR/xpath-functions-31/#func-map-get + registerFunction(MapGet.SIGNATURE); + // https://www.w3.org/TR/xpath-functions-31/#func-map-find + registerFunction(MapFind.SIGNATURE); + // https://www.w3.org/TR/xpath-functions-31/#func-map-put + registerFunction(MapPut.SIGNATURE); + // https://www.w3.org/TR/xpath-functions-31/#func-map-entry + registerFunction(MapEntry.SIGNATURE); + // https://www.w3.org/TR/xpath-functions-31/#func-map-remove + registerFunction(MapRemove.SIGNATURE); + // P3: https://www.w3.org/TR/xpath-functions-31/#func-map-for-each + + // // xpath casting functions + // registerFunction( + // CastFunction.signature(MetapathConstants.NS_XML_SCHEMA, "boolean", + // IBooleanItem.class, IBooleanItem::cast)); + // registerFunction(CastFunction.signature( + // MetapathConstants.NS_XML_SCHEMA, "date", IDateItem.class, IDateItem::cast)); + // registerFunction(CastFunction.signature( + // MetapathConstants.NS_XML_SCHEMA, "dateTime", IDateTimeItem.class, + // IDateTimeItem::cast)); + // registerFunction(CastFunction.signature( + // MetapathConstants.NS_XML_SCHEMA, "decimal", IDecimalItem.class, + // IDecimalItem::cast)); + // registerFunction(CastFunction.signature( + // MetapathConstants.NS_XML_SCHEMA, "duration", IDurationItem.class, + // IDurationItem::cast)); + // registerFunction(CastFunction.signature( + // MetapathConstants.NS_XML_SCHEMA, "integer", IIntegerItem.class, + // IIntegerItem::cast)); + // registerFunction(CastFunction.signature( + // MetapathConstants.NS_XML_SCHEMA, "NCName", INcNameItem.class, + // INcNameItem::cast)); + // registerFunction(CastFunction.signature( + // MetapathConstants.NS_XML_SCHEMA, "nonNegativeInteger", + // INonNegativeIntegerItem.class, + // INonNegativeIntegerItem::cast)); + // registerFunction(CastFunction.signature( + // MetapathConstants.NS_XML_SCHEMA, "positiveInteger", + // IPositiveIntegerItem.class, + // IPositiveIntegerItem::cast)); + // registerFunction(CastFunction.signature( + // MetapathConstants.NS_XML_SCHEMA, "string", IStringItem.class, + // IStringItem::cast)); // metapath casting functions registerFunction(CastFunction.signature( diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnAbs.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnAbs.java index 0d0a999f8..98c99d588 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnAbs.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnAbs.java @@ -76,10 +76,9 @@ private static ISequence execute( @NonNull List> arguments, @NonNull DynamicContext dynamicContext, IItem focus) { - ISequence sequence = FunctionUtils.asType( - ObjectUtils.requireNonNull(arguments.get(0))); + ISequence sequence = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0))); - INumericItem item = FunctionUtils.getFirstItem(sequence, true); + INumericItem item = sequence.getFirstItem(true); if (item == null) { return ISequence.empty(); // NOPMD - readability } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnAvg.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnAvg.java index 2f829a3c5..a392a53de 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnAvg.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnAvg.java @@ -93,7 +93,7 @@ private static ISequence execute( ISequence sequence = FunctionUtils.asType( ObjectUtils.requireNonNull(arguments.get(0))); - List items = sequence.asList(); + List items = sequence.getValue(); return ISequence.of(average(items)); } @@ -163,7 +163,7 @@ public static IAnyAtomicItem average(@NonNull Collection type.getName()) + .map(Class::getName) .collect(CustomCollectors.joiningWithOxfordComma(",")))); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnBaseUri.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnBaseUri.java index 91486eda6..e193bbe9c 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnBaseUri.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnBaseUri.java @@ -101,7 +101,7 @@ private static ISequence executeOneArg(@NonNull IFunction function, ISequence arg = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0))); - INodeItem item = FunctionUtils.getFirstItem(arg, true); + INodeItem item = arg.getFirstItem(true); return ISequence.of(fnBaseUri(item)); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnBoolean.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnBoolean.java index 4d044095a..bafdf43b4 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnBoolean.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnBoolean.java @@ -29,7 +29,6 @@ import gov.nist.secauto.metaschema.core.metapath.DynamicContext; import gov.nist.secauto.metaschema.core.metapath.ISequence; import gov.nist.secauto.metaschema.core.metapath.MetapathConstants; -import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils; import gov.nist.secauto.metaschema.core.metapath.function.IArgument; import gov.nist.secauto.metaschema.core.metapath.function.IFunction; import gov.nist.secauto.metaschema.core.metapath.function.InvalidArgumentFunctionException; @@ -109,7 +108,7 @@ public static IBooleanItem fnBoolean(@NonNull ISequence sequence) { */ public static boolean fnBooleanAsPrimitive(@NonNull ISequence sequence) { boolean retval = false; - IItem first = FunctionUtils.getFirstItem(sequence, false); + IItem first = sequence.getFirstItem(false); if (first != null) { if (first instanceof INodeItem) { retval = true; 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 215ede52b..7d847da3e 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 @@ -79,7 +79,7 @@ private static ISequence execute( ISequence sequence = FunctionUtils.asType( ObjectUtils.requireNonNull(arguments.get(0))); - INumericItem item = FunctionUtils.getFirstItem(sequence, true); + INumericItem item = sequence.getFirstItem(true); if (item == null) { return ISequence.empty(); // NOPMD - readability } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnCompare.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnCompare.java index ad5fc26b6..f6fbf7516 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnCompare.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnCompare.java @@ -35,7 +35,6 @@ import gov.nist.secauto.metaschema.core.metapath.item.IItem; import gov.nist.secauto.metaschema.core.metapath.item.atomic.IIntegerItem; import gov.nist.secauto.metaschema.core.metapath.item.atomic.IStringItem; -import gov.nist.secauto.metaschema.core.util.ObjectUtils; import java.util.List; @@ -80,11 +79,8 @@ private static ISequence execute( @NonNull List> arguments, @NonNull DynamicContext dynamicContext, IItem focus) { - IStringItem comparand1 = FunctionUtils.getFirstItem( - FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0))), true); - - IStringItem comparand2 = FunctionUtils.getFirstItem( - FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(1))), true); + IStringItem comparand1 = FunctionUtils.asTypeOrNull(arguments.get(0).getFirstItem(true)); + IStringItem comparand2 = FunctionUtils.asTypeOrNull(arguments.get(1).getFirstItem(true)); ISequence retval; if (comparand1 == null || comparand2 == null) { diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnConcat.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnConcat.java index 56eaf357f..42594b5f9 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnConcat.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnConcat.java @@ -29,7 +29,6 @@ import gov.nist.secauto.metaschema.core.metapath.DynamicContext; import gov.nist.secauto.metaschema.core.metapath.ISequence; import gov.nist.secauto.metaschema.core.metapath.MetapathConstants; -import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils; import gov.nist.secauto.metaschema.core.metapath.function.IArgument; import gov.nist.secauto.metaschema.core.metapath.function.IFunction; import gov.nist.secauto.metaschema.core.metapath.item.IItem; @@ -87,7 +86,7 @@ private static ISequence execute( return ISequence.of(concat(ObjectUtils.notNull(arguments.stream() .map(arg -> { assert arg != null; - return (IAnyAtomicItem) FunctionUtils.getFirstItem(arg, true); + return (IAnyAtomicItem) arg.getFirstItem(true); })))); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnData.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnData.java index f860e9bf2..54c2619ca 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnData.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnData.java @@ -36,6 +36,7 @@ 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.IAtomicValuedItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.IArrayItem; import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem; import gov.nist.secauto.metaschema.core.util.ObjectUtils; @@ -126,11 +127,9 @@ private static ISequence executeOneArg( */ @SuppressWarnings("null") @NonNull - public static ISequence fnData(@NonNull ISequence sequence) { - @NonNull Stream stream = sequence.asStream(); - return ISequence.of(stream.flatMap(x -> { - return Stream.of(fnDataItem(x)); - })); + public static ISequence fnData(@NonNull ISequence sequence) { + return ISequence.of(sequence.stream() + .flatMap(FnData::atomize)); } /** @@ -145,13 +144,60 @@ public static ISequence fnData(@NonNull ISequence sequence) { @NonNull public static IAnyAtomicItem fnDataItem(@NonNull IItem item) { IAnyAtomicItem retval = null; - if (item instanceof IAnyAtomicItem) { - retval = (IAnyAtomicItem) item; - } else if (item instanceof IAtomicValuedItem) { + if (item instanceof IAtomicValuedItem) { retval = ((IAtomicValuedItem) item).toAtomicItem(); } - if (retval == null) { + if (retval != null) { + return retval; + } + throw new InvalidTypeFunctionException(InvalidTypeFunctionException.NODE_HAS_NO_TYPED_VALUE, item); + } + + /** + * An implementation of + * item + * atomization. + * + * @param item + * the item to atomize + * @return the atomized result + */ + @NonNull + public static Stream fnDataItem(@NonNull IArrayItem item) { + return ObjectUtils.notNull(item.stream().flatMap(member -> { + Stream result; + if (member instanceof IItem) { + result = atomize((IItem) member); + } else if (member instanceof ISequence) { + result = ((ISequence) member).stream() + .flatMap(FnData::atomize); + } else { + throw new UnsupportedOperationException("array member not an item or sequence."); + } + return result; + })); + } + + /** + * An implementation of + * item + * atomization. + * + * @param item + * the item to atomize + * @return the atomized result + */ + @NonNull + public static Stream atomize(@NonNull IItem item) { + Stream retval; + if (item instanceof IAnyAtomicItem) { + retval = ObjectUtils.notNull(Stream.of((IAnyAtomicItem) item)); + } else if (item instanceof IAtomicValuedItem) { + retval = ObjectUtils.notNull(Stream.of(((IAtomicValuedItem) item).toAtomicItem())); + } else if (item instanceof IArrayItem) { + retval = fnDataItem((IArrayItem) item); + } else { throw new InvalidTypeFunctionException(InvalidTypeFunctionException.NODE_HAS_NO_TYPED_VALUE, item); } return retval; diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnDoc.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnDoc.java index efb74b3a0..049e4b58e 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnDoc.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnDoc.java @@ -76,7 +76,7 @@ private static ISequence execute(@NonNull IFunction function, IItem focus) { ISequence arg = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0))); - IStringItem item = FunctionUtils.getFirstItem(arg, true); + IStringItem item = arg.getFirstItem(true); return item == null ? ISequence.empty() : ISequence.of(fnDoc(item, dynamicContext)); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnDocumentUri.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnDocumentUri.java index 2e02b919e..64c8f602f 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnDocumentUri.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnDocumentUri.java @@ -88,14 +88,9 @@ private static ISequence executeNoArg(@NonNull IFunction function, INodeItem item = FunctionUtils.requireTypeOrNull(INodeItem.class, focus); - ISequence retval; - if (item instanceof IDocumentNodeItem) { - IAnyUriItem uri = fnDocumentUri((IDocumentNodeItem) item); - retval = ISequence.of(uri); - } else { - retval = ISequence.empty(); - } - return retval; + return item instanceof IDocumentNodeItem + ? ISequence.of(fnDocumentUri((IDocumentNodeItem) item)) + : ISequence.empty(); } @SuppressWarnings("unused") @@ -107,18 +102,11 @@ private static ISequence executeOneArg(@NonNull IFunction function, ISequence arg = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0))); - INodeItem item = FunctionUtils.getFirstItem(arg, true); - - ISequence retval; - if (item == null) { - retval = ISequence.empty(); - } else if (item instanceof IDocumentNodeItem) { - IAnyUriItem uri = fnDocumentUri((IDocumentNodeItem) item); - retval = ISequence.of(uri); - } else { - retval = ISequence.empty(); - } - return retval; + INodeItem item = arg.getFirstItem(true); + + return item instanceof IDocumentNodeItem + ? ISequence.of(fnDocumentUri((IDocumentNodeItem) item)) + : ISequence.empty(); } /** diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnInsertBefore.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnInsertBefore.java index 0189f99a0..879a37f27 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnInsertBefore.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnInsertBefore.java @@ -84,11 +84,10 @@ private static ISequence execute(@NonNull IFunction function, @NonNull DynamicContext dynamicContext, IItem focus) { ISequence target = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0))); - IIntegerItem position - = ObjectUtils.requireNonNull( - FunctionUtils.getFirstItem(FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(1))), true)); + + IIntegerItem position = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(1).getFirstItem(true))); ISequence inserts = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(2))); - return ISequence.of(fnInsertBefore(target, position, inserts)); + return ISequence.ofCollection(fnInsertBefore(target, position, inserts)); } /** 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 0035a917e..8953bcad3 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 @@ -101,7 +101,7 @@ private static ISequence executeMin( ISequence sequence = FunctionUtils.asType( ObjectUtils.requireNonNull(arguments.get(0))); - return ISequence.of(min(sequence.asList())); + return ISequence.of(min(sequence.getValue())); } @SuppressWarnings("unused") @@ -114,7 +114,7 @@ private static ISequence executeMax( ISequence sequence = FunctionUtils.asType( ObjectUtils.requireNonNull(arguments.get(0))); - return ISequence.of(max(sequence.asList())); + return ISequence.of(max(sequence.getValue())); } /** @@ -179,7 +179,7 @@ private static Stream normalize( int size = resultingItems.size(); if (counts.getOrDefault(IStringItem.class, 0) + counts.getOrDefault(IAnyUriItem.class, 0) == size) { stream = resultingItems.stream() - .map(item -> item.asStringItem()); + .map(IAnyAtomicItem::asStringItem); } else if (counts.getOrDefault(IDecimalItem.class, 0) == size) { stream = resultingItems.stream() .map(item -> (IDecimalItem) item); @@ -191,7 +191,7 @@ private static Stream normalize( InvalidArgumentFunctionException.INVALID_ARGUMENT_TYPE, String.format("Values must all be of a single atomic type. Their types are '%s'.", FunctionUtils.getTypes(resultingItems).stream() - .map(clazz -> clazz.getName()) + .map(Class::getName) .collect(Collectors.joining(",")))); } return stream; diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnPath.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnPath.java index 1242f9bbc..bd06bdd36 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnPath.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnPath.java @@ -121,7 +121,7 @@ private static ISequence executeOneArg(@NonNull IFunction function, */ @NonNull public static ISequence fnPath(@NonNull ISequence sequence) { - IItem item = FunctionUtils.getFirstItem(sequence, true); + IItem item = sequence.getFirstItem(true); ISequence retval; if (item == null) { diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnRemove.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnRemove.java index 9568d11d3..73f666bf2 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnRemove.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnRemove.java @@ -79,10 +79,8 @@ private static ISequence execute(@NonNull IFunction function, @NonNull DynamicContext dynamicContext, IItem focus) { ISequence target = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0))); - IIntegerItem position - = ObjectUtils.requireNonNull( - FunctionUtils.getFirstItem(FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(1))), true)); - return ISequence.of(fnRemove(target, position)); + IIntegerItem position = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(1).getFirstItem(true))); + return ISequence.ofCollection(fnRemove(target, position)); } /** diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnResolveUri.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnResolveUri.java index fbfe91ec3..210932977 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnResolveUri.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnResolveUri.java @@ -102,7 +102,7 @@ private static ISequence executeOneArg( return ISequence.empty(); // NOPMD - readability } - IStringItem relativeString = FunctionUtils.getFirstItem(relativeSequence, true); + IStringItem relativeString = relativeSequence.getFirstItem(true); IAnyUriItem resolvedUri = null; if (relativeString != null) { resolvedUri = fnResolveUri(relativeString, null, dynamicContext); @@ -143,7 +143,7 @@ private static ISequence executeTwoArg( } ISequence baseSequence = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(1))); - IStringItem baseString = FunctionUtils.getFirstItem(baseSequence, true); + IStringItem baseString = baseSequence.getFirstItem(true); if (baseString == null) { throw new InvalidArgumentFunctionException( @@ -152,7 +152,7 @@ private static ISequence executeTwoArg( } IAnyUriItem baseUri = IAnyUriItem.cast(baseString); - IStringItem relativeString = FunctionUtils.getFirstItem(relativeSequence, true); + IStringItem relativeString = relativeSequence.getFirstItem(true); IAnyUriItem resolvedUri = null; if (relativeString != null) { diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnReverse.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnReverse.java index 5c6b39fa4..8fac330e3 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnReverse.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnReverse.java @@ -74,7 +74,7 @@ private static ISequence execute(@NonNull IFunction function, @NonNull DynamicContext dynamicContext, IItem focus) { ISequence target = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0))); - return ISequence.of(fnReverse(target)); + return ISequence.ofCollection(fnReverse(target)); } /** diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnRound.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnRound.java index 5edef5cf5..7b39a3643 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnRound.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnRound.java @@ -102,7 +102,7 @@ private static ISequence executeOneArg( ISequence sequence = FunctionUtils.asType( ObjectUtils.requireNonNull(arguments.get(0))); - INumericItem item = FunctionUtils.getFirstItem(sequence, true); + INumericItem item = sequence.getFirstItem(true); if (item == null) { return ISequence.empty(); // NOPMD - readability } @@ -120,15 +120,12 @@ private static ISequence executeTwoArg( ISequence sequence = FunctionUtils.asType( ObjectUtils.requireNonNull(arguments.get(0))); - INumericItem item = FunctionUtils.getFirstItem(sequence, true); + INumericItem item = sequence.getFirstItem(true); if (item == null) { return ISequence.empty(); // NOPMD - readability } - IIntegerItem precision = FunctionUtils.asType( - FunctionUtils.requireFirstItem( - ObjectUtils.requireNonNull(arguments.get(1)), - true)); + IIntegerItem precision = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(1).getFirstItem(true))); return ISequence.of(item.round(precision)); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnStartsWith.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnStartsWith.java index 33320a005..43faba83d 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnStartsWith.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnStartsWith.java @@ -35,7 +35,6 @@ import gov.nist.secauto.metaschema.core.metapath.item.IItem; 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.util.ObjectUtils; import java.util.List; @@ -48,6 +47,9 @@ public final class FnStartsWith { static final IFunction SIGNATURE = IFunction.builder() .name("starts-with") .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS) + .deterministic() + .contextDependent() + .focusIndependent() .argument(IArgument.builder() .name("arg1").type(IStringItem.class) .zeroOrOne() @@ -68,10 +70,9 @@ private static ISequence execute(@NonNull IFunction function, @NonNull List> arguments, @NonNull DynamicContext dynamicContext, IItem focus) { - IStringItem arg1 = FunctionUtils.getFirstItem( - FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0))), true); - IStringItem arg2 = FunctionUtils.getFirstItem( - FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(1))), true); + IStringItem arg1 = FunctionUtils.asTypeOrNull(arguments.get(0).getFirstItem(true)); + + IStringItem arg2 = FunctionUtils.asTypeOrNull(arguments.get(1).getFirstItem(true)); return ISequence.of(fnStartsWith(arg1, arg2)); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnStaticBaseUri.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnStaticBaseUri.java index 1fc6a1b73..9e5565fdf 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnStaticBaseUri.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnStaticBaseUri.java @@ -46,6 +46,9 @@ public final class FnStaticBaseUri { static final IFunction SIGNATURE = IFunction.builder() .name("static-base-uri") .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS) + .deterministic() + .contextDependent() + .focusIndependent() .argument(IArgument.builder() .name("arg1") .type(IStringItem.class) diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnSum.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnSum.java index 93c418e83..2275c7ee4 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnSum.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnSum.java @@ -105,7 +105,7 @@ private static ISequence executeOneArg( ISequence sequence = FunctionUtils.asType( ObjectUtils.requireNonNull(arguments.get(0))); - return ISequence.of(sum(sequence.asList(), IIntegerItem.ZERO)); + return ISequence.of(sum(sequence.getValue(), IIntegerItem.ZERO)); } @SuppressWarnings("unused") @@ -115,15 +115,11 @@ private static ISequence executeTwoArg( @NonNull List> arguments, @NonNull DynamicContext dynamicContext, IItem focus) { - ISequence sequence = FunctionUtils.asType( - ObjectUtils.requireNonNull(arguments.get(0))); + ISequence sequence = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0))); - IAnyAtomicItem zero = FunctionUtils.getFirstItem( - FunctionUtils.asType( - ObjectUtils.requireNonNull(arguments.get(1))), - true); + IAnyAtomicItem zero = FunctionUtils.asTypeOrNull(arguments.get(1).getFirstItem(true)); - return ISequence.of(sum(sequence.asList(), zero)); + return ISequence.of(sum(sequence.getValue(), zero)); } /** @@ -208,7 +204,7 @@ public static IAnyAtomicItem sum( InvalidArgumentFunctionException.INVALID_ARGUMENT_TYPE, String.format("Values must all be of type '%s'.", OperationFunctions.AGGREGATE_MATH_TYPES.stream() - .map(type -> type.getName()) + .map(Class::getName) .collect(CustomCollectors.joiningWithOxfordComma(",")))); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnTail.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnTail.java index 1f07291d6..0ecb66551 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnTail.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnTail.java @@ -73,7 +73,7 @@ private static ISequence execute(@NonNull IFunction function, @NonNull DynamicContext dynamicContext, IItem focus) { ISequence items = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0))); - return ISequence.of(fnTail(items)); + return ISequence.ofCollection(fnTail(items)); } /** diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapContains.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapContains.java new file mode 100644 index 000000000..b9639d970 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapContains.java @@ -0,0 +1,102 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.function.library; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ICollectionValue; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.MetapathConstants; +import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils; +import gov.nist.secauto.metaschema.core.metapath.function.IArgument; +import gov.nist.secauto.metaschema.core.metapath.function.IFunction; +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.IBooleanItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.IMapItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.List; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public final class MapContains { + @NonNull + public static final IFunction SIGNATURE = IFunction.builder() + .name("contains") + .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS_MAP) + .deterministic() + .contextIndependent() + .focusIndependent() + .argument(IArgument.builder() + .name("map") + .type(IMapItem.class) + .one() + .build()) + .argument(IArgument.builder() + .name("key") + .type(IAnyAtomicItem.class) + .one() + .build()) + .returnType(IBooleanItem.class) + .returnOne() + .functionHandler(MapContains::execute) + .build(); + + private MapContains() { + // disable construction + } + + @SuppressWarnings("unused") + @NonNull + private static ISequence execute(@NonNull IFunction function, + @NonNull List> arguments, + @NonNull DynamicContext dynamicContext, + IItem focus) { + IMapItem map = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0).getFirstItem(true))); + IAnyAtomicItem key = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(1).getFirstItem(true))); + + return IBooleanItem.valueOf(contains(map, key)).asSequence(); + } + + /** + * An implementation of XPath 3.1 map:contains. + * + * @param + * the type of items in the given Metapath map + * @param map + * the map of Metapath items that is the target of retrieval + * @param key + * the key for the item to retrieve + * @return {@code true} if the key exists in the map, or {@code false} otherwise + */ + public static boolean contains( + @NonNull IMapItem map, + @NonNull IAnyAtomicItem key) { + return map.get(key.asMapKey()) != null; + } +} 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 new file mode 100644 index 000000000..c1e018a3e --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapEntry.java @@ -0,0 +1,102 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.function.library; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ICollectionValue; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.MetapathConstants; +import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils; +import gov.nist.secauto.metaschema.core.metapath.function.IArgument; +import gov.nist.secauto.metaschema.core.metapath.function.IFunction; +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.function.IMapItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.List; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public final class MapEntry { + @NonNull + public static final IFunction SIGNATURE = IFunction.builder() + .name("entry") + .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS_MAP) + .deterministic() + .contextIndependent() + .focusIndependent() + .argument(IArgument.builder() + .name("key") + .type(IAnyAtomicItem.class) + .one() + .build()) + .argument(IArgument.builder() + .name("item") + .type(IItem.class) + .zeroOrMore() + .build()) + .returnType(IItem.class) + .returnOne() + .functionHandler(MapEntry::execute) + .build(); + + private MapEntry() { + // disable construction + } + + @SuppressWarnings("unused") + @NonNull + private static ISequence> execute(@NonNull IFunction function, + @NonNull List> arguments, + @NonNull DynamicContext dynamicContext, + IItem focus) { + IAnyAtomicItem key = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0).getFirstItem(true))); + @SuppressWarnings("unchecked") T value = (T) arguments.get(1).toCollectionValue(); + + return entry(key, value).asSequence(); + } + + /** + * An implementation of XPath 3.1 map:entry. + * + * @param + * the type of items in the given Metapath map + * @param key + * the Metapath map entry key + * @param value + * the Metapath map entry value + * @return a new array containing the modification + */ + @NonNull + public static IMapItem entry( + @NonNull IAnyAtomicItem key, + @NonNull T value) { + return IMapItem.ofEntries(IMapItem.entry(key, value)); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapFind.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapFind.java new file mode 100644 index 000000000..2b1bd6b22 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapFind.java @@ -0,0 +1,157 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.function.library; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ICollectionValue; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.MetapathConstants; +import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils; +import gov.nist.secauto.metaschema.core.metapath.function.IArgument; +import gov.nist.secauto.metaschema.core.metapath.function.IFunction; +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.function.IArrayItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.IMapItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public final class MapFind { + @NonNull + public static final IFunction SIGNATURE = IFunction.builder() + .name("find") + .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS_MAP) + .deterministic() + .contextIndependent() + .focusIndependent() + .argument(IArgument.builder() + .name("input") + .type(IItem.class) + .zeroOrMore() + .build()) + .argument(IArgument.builder() + .name("key") + .type(IAnyAtomicItem.class) + .one() + .build()) + .returnType(IArrayItem.class) + .returnOne() + .functionHandler(MapFind::execute) + .build(); + + private MapFind() { + // disable construction + } + + @SuppressWarnings("unused") + @NonNull + private static ISequence execute(@NonNull IFunction function, + @NonNull List> arguments, + @NonNull DynamicContext dynamicContext, + IItem focus) { + ISequence input = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0))); + IAnyAtomicItem key = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(1).getFirstItem(true))); + + return ISequence.of(IArrayItem.ofCollection( + ObjectUtils.notNull(find((Collection) input, key) + .collect(Collectors.toList())))); + } + + /** + * An implementation of XPath 3.1 map:find. + * + * @param input + * the item sequence to search for key matches + * @param key + * the key for the item to retrieve + * @return the retrieved item + */ + @NonNull + public static Stream find( + @NonNull Collection input, + @NonNull IAnyAtomicItem key) { + return ObjectUtils.notNull(input.stream() + // handle item + .flatMap(item -> find(ObjectUtils.notNull(item), key))); + } + + @NonNull + public static Stream find( + @NonNull IItem item, + @NonNull IAnyAtomicItem key) { + Stream retval; + if (item instanceof IArrayItem) { + IArrayItem array = (IArrayItem) item; + retval = ObjectUtils.notNull(array.stream() + // handle array values + .flatMap(value -> find(ObjectUtils.notNull(value), key))); + } else if (item instanceof IMapItem) { + IMapItem map = (IMapItem) item; + // handle map + retval = find(map, key); + } else { + // do nothing + retval = ObjectUtils.notNull(Stream.empty()); + } + return retval; + } + + @NonNull + private static Stream find( + @NonNull ICollectionValue value, + @NonNull IAnyAtomicItem key) { + Stream retval; + if (value instanceof ISequence) { + ISequence sequence = (ISequence) value; + // handle sequence items + retval = find((Collection) sequence, key); + } else { + // handle item + retval = find((IItem) value, key); + } + return retval; + } + + @NonNull + public static Stream find( + @NonNull IMapItem map, + @NonNull IAnyAtomicItem key) { + return ObjectUtils.notNull(Stream.concat( + // add matching value, if it exists + Stream.ofNullable(MapGet.get(map, key)), + map.values().stream() + // handle map values + .flatMap(value -> find(ObjectUtils.notNull(value), key)))); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapGet.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapGet.java new file mode 100644 index 000000000..60c69716d --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapGet.java @@ -0,0 +1,104 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.function.library; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ICollectionValue; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.MetapathConstants; +import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils; +import gov.nist.secauto.metaschema.core.metapath.function.IArgument; +import gov.nist.secauto.metaschema.core.metapath.function.IFunction; +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.function.IMapItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.List; + +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; + +public final class MapGet { + @NonNull + public static final IFunction SIGNATURE = IFunction.builder() + .name("get") + .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS_MAP) + .deterministic() + .contextIndependent() + .focusIndependent() + .argument(IArgument.builder() + .name("map") + .type(IMapItem.class) + .one() + .build()) + .argument(IArgument.builder() + .name("key") + .type(IAnyAtomicItem.class) + .one() + .build()) + .returnType(IItem.class) + .returnZeroOrOne() + .functionHandler(MapGet::execute) + .build(); + + private MapGet() { + // disable construction + } + + @SuppressWarnings("unused") + @NonNull + private static ISequence execute(@NonNull IFunction function, + @NonNull List> arguments, + @NonNull DynamicContext dynamicContext, + IItem focus) { + IMapItem map = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0).getFirstItem(true))); + IAnyAtomicItem key = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(1).getFirstItem(true))); + + ICollectionValue value = get(map, key); + return value == null ? ISequence.empty() : value.asSequence(); + } + + /** + * An implementation of XPath 3.1 map:get. + * + * @param + * the type of items in the given Metapath map + * @param map + * the map of Metapath items that is the target of retrieval + * @param key + * the key for the item to retrieve + * @return the retrieved item + */ + @Nullable + public static V get( + @NonNull IMapItem map, + @NonNull IAnyAtomicItem key) { + return map.get(key.asMapKey()); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapKeys.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapKeys.java new file mode 100644 index 000000000..deef6fc93 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapKeys.java @@ -0,0 +1,96 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.function.library; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.MetapathConstants; +import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils; +import gov.nist.secauto.metaschema.core.metapath.function.IArgument; +import gov.nist.secauto.metaschema.core.metapath.function.IFunction; +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.function.IMapItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public final class MapKeys { + @NonNull + static final IFunction SIGNATURE = IFunction.builder() + .name("keys") + .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS_MAP) + .deterministic() + .contextIndependent() + .focusIndependent() + .argument(IArgument.builder() + .name("map") + .type(IMapItem.class) + .one() + .build()) + .returnType(IAnyAtomicItem.class) + .returnZeroOrMore() + .functionHandler(MapKeys::execute) + .build(); + + private MapKeys() { + // disable construction + } + + /** + * An implementation of XPath 3.1 map:size. + * + * @param array + * the arrays to join + * @return a new combined array + */ + @SuppressWarnings("unused") + @NonNull + private static ISequence execute(@NonNull IFunction function, + @NonNull List> arguments, + @NonNull DynamicContext dynamicContext, + IItem focus) { + IMapItem map = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0).getFirstItem(true))); + + return ISequence.of(keys(map)); + } + + public static Stream keys(@NonNull IMapItem map) { + return keys((Map) map); + } + + public static Stream keys(@NonNull Map map) { + return map.keySet().stream() + .map(IMapKey::getKey); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapMerge.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapMerge.java new file mode 100644 index 000000000..d5b030682 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapMerge.java @@ -0,0 +1,226 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.function.library; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ICollectionValue; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.MetapathConstants; +import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils; +import gov.nist.secauto.metaschema.core.metapath.function.IArgument; +import gov.nist.secauto.metaschema.core.metapath.function.IFunction; +import gov.nist.secauto.metaschema.core.metapath.function.JsonFunctionException; +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.IStringItem; +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.CollectionUtil; +import gov.nist.secauto.metaschema.core.util.CustomCollectors; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.stream.Stream; + +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; + +public final class MapMerge { + private static final Random RANDOM = new Random(); + private static final IMapKey DUPLICATES_OPTION = IStringItem.valueOf("duplicates").asMapKey(); + + @NonNull + static final IFunction SIGNATURE_ONE_ARG = IFunction.builder() + .name("merge") + .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS_MAP) + .deterministic() + .contextIndependent() + .focusIndependent() + .argument(IArgument.builder() + .name("maps") + .type(IMapItem.class) + .zeroOrMore() + .build()) + .returnType(IMapItem.class) + .returnOne() + .functionHandler(MapMerge::executeOneArg) + .build(); + + @NonNull + static final IFunction SIGNATURE_TWO_ARG = IFunction.builder() + .name("merge") + .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS_MAP) + .deterministic() + .contextIndependent() + .focusIndependent() + .argument(IArgument.builder() + .name("maps") + .type(IMapItem.class) + .zeroOrMore() + .build()) + .argument(IArgument.builder() + .name("options") + .type(IMapItem.class) + .one() + .build()) + .returnType(IMapItem.class) + .returnOne() + .functionHandler(MapMerge::executeTwoArg) + .build(); + + private enum Duplicates { + REJECT("reject", (key, v1, v2) -> { + throw new JsonFunctionException( + JsonFunctionException.DUPLICATE_KEYS, + String.format("Duplicate key '%s' not allowed.", key.getKey().asString())); + }), + + USE_FIRST("use-first", (key, v1, v2) -> v1), + USE_LAST("use-last", (key, v1, v2) -> v2), + USE_ANY("use-any", (key, v1, v2) -> RANDOM.nextBoolean() ? v1 : v2), + COMBINE( + "combine", + (key, v1, v2) -> Stream.concat(v1.asSequence().stream(), v2.asSequence().stream()) + .collect(ISequence.toSequence())); + + private static final Map BY_NAME; + + @NonNull + private final String name; + @NonNull + private final CustomCollectors.DuplicateHandler duplicateHander; + + static { + Map map = new HashMap<>(); + for (Duplicates value : values()) { + map.put(value.getName(), value); + } + BY_NAME = Collections.unmodifiableMap(map); + } + + @Nullable + public static Duplicates lookup(@NonNull String name) { + return BY_NAME.get(name); + } + + Duplicates(@NonNull String name, + @NonNull CustomCollectors.DuplicateHandler duplicateHander) { + this.name = name; + this.duplicateHander = duplicateHander; + } + + public String getName() { + return name; + } + + public CustomCollectors.DuplicateHandler getDuplicateHander() { + return duplicateHander; + } + } + + private MapMerge() { + // disable construction + } + + @SuppressWarnings("unused") + @NonNull + private static ISequence executeOneArg(@NonNull IFunction function, + @NonNull List> arguments, + @NonNull DynamicContext dynamicContext, + IItem focus) { + ISequence> maps = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0))); + + return ISequence.of(merge(maps, CollectionUtil.emptyMap())); + } + + @SuppressWarnings("unused") + @NonNull + private static ISequence executeTwoArg(@NonNull IFunction function, + @NonNull List> arguments, + @NonNull DynamicContext dynamicContext, + IItem focus) { + ISequence> maps = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0))); + IMapItem options = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(1).getFirstItem(true))); + + return ISequence.of(merge(maps, options)); + } + + /** + * An implementation of XPath 3.1 array:flatten. + * + * @param maps + * a collection of maps to merge + * @param options + * settings that affect the merge behavior + * @return a map containing the merged entries + */ + @SuppressWarnings("null") + @NonNull + public static IMapItem merge(@NonNull Collection> maps, + @NonNull Map options) { + if (maps.isEmpty()) { + return IMapItem.empty(); + } + + // handle the "duplicates" option + ICollectionValue duplicatesOption = options.get(DUPLICATES_OPTION); + + Duplicates duplicates; + if (duplicatesOption == null) { + // default option + duplicates = Duplicates.USE_FIRST; + } else { + // resolve the provided option + IAnyAtomicItem atomicValue = FnData.fnData(duplicatesOption.asSequence()).getFirstItem(true); + if (atomicValue == null) { + throw new JsonFunctionException( + JsonFunctionException.INVALID_OPTION, + String.format("Missing '%s' option value.", DUPLICATES_OPTION.getKey().asString())); + } + String duplicatesValue = IStringItem.cast(atomicValue).asString(); + duplicates = Duplicates.lookup(duplicatesValue); + if (duplicates == null) { + throw new JsonFunctionException( + JsonFunctionException.INVALID_OPTION, + String.format("Invalid '%s' option value '%s'.", DUPLICATES_OPTION.getKey().asString(), duplicatesValue)); + } + } + + // merge the maps + return IMapItem.ofCollection(maps.stream() + .flatMap(map -> map.entrySet().stream()) + // collect the entries into a new map + .collect(CustomCollectors.toMap(Map.Entry::getKey, Map.Entry::getValue, duplicates.getDuplicateHander(), + HashMap::new))); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapPut.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapPut.java new file mode 100644 index 000000000..84013f091 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapPut.java @@ -0,0 +1,117 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.function.library; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ICollectionValue; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.MetapathConstants; +import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils; +import gov.nist.secauto.metaschema.core.metapath.function.IArgument; +import gov.nist.secauto.metaschema.core.metapath.function.IFunction; +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.function.IMapItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public final class MapPut { + @NonNull + public static final IFunction SIGNATURE = IFunction.builder() + .name("put") + .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS_MAP) + .deterministic() + .contextIndependent() + .focusIndependent() + .argument(IArgument.builder() + .name("map") + .type(IMapItem.class) + .one() + .build()) + .argument(IArgument.builder() + .name("key") + .type(IAnyAtomicItem.class) + .one() + .build()) + .argument(IArgument.builder() + .name("value") + .type(IItem.class) + .zeroOrMore() + .build()) + .returnType(IMapItem.class) + .returnOne() + .functionHandler(MapPut::execute) + .build(); + + private MapPut() { + // disable construction + } + + @SuppressWarnings("unused") + @NonNull + private static ISequence execute(@NonNull IFunction function, + @NonNull List> arguments, + @NonNull DynamicContext dynamicContext, + IItem focus) { + IMapItem map = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0).getFirstItem(true))); + IAnyAtomicItem key = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(1).getFirstItem(true))); + @SuppressWarnings("unchecked") V value = (V) ObjectUtils.requireNonNull(arguments.get(2)).toCollectionValue(); + + return put(map, key, value).asSequence(); + } + + /** + * An implementation of XPath 3.1 map:put. + * + * @param + * the type of items in the given Metapath map + * @param map + * the map of Metapath items that is to be modified + * @param key + * the key for the value to add to the map + * @param value + * the value to add to the map + * @return the modified map + */ + @NonNull + public static IMapItem put( + @NonNull IMapItem map, + @NonNull IAnyAtomicItem key, + @NonNull V value) { + Map copy = new HashMap<>(map); + copy.put(key.asMapKey(), value); + + return IMapItem.ofCollection(copy); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapRemove.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapRemove.java new file mode 100644 index 000000000..313c939b4 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapRemove.java @@ -0,0 +1,115 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.function.library; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ICollectionValue; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.MetapathConstants; +import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils; +import gov.nist.secauto.metaschema.core.metapath.function.IArgument; +import gov.nist.secauto.metaschema.core.metapath.function.IFunction; +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.function.IMapItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public final class MapRemove { + @NonNull + public static final IFunction SIGNATURE = IFunction.builder() + .name("remove") + .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS_MAP) + .deterministic() + .contextIndependent() + .focusIndependent() + .argument(IArgument.builder() + .name("map") + .type(IMapItem.class) + .one() + .build()) + .argument(IArgument.builder() + .name("keys") + .type(IAnyAtomicItem.class) + .zeroOrMore() + .build()) + .returnType(IMapItem.class) + .returnOne() + .functionHandler(MapRemove::execute) + .build(); + + private MapRemove() { + // disable construction + } + + @SuppressWarnings("unused") + @NonNull + private static ISequence execute(@NonNull IFunction function, + @NonNull List> arguments, + @NonNull DynamicContext dynamicContext, + IItem focus) { + IMapItem map = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0).getFirstItem(true))); + ISequence keys = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(1))); + + return ISequence.of(removeItems(map, keys)); + } + + /** + * An implementation of XPath 3.1 map:remove. + * + * @param + * the type of items in the given Metapath map + * @param map + * the map of Metapath items that is to be modified + * @param keys + * the keys to remove from the map + * @return the modified map + */ + @NonNull + public static IMapItem removeItems( + @NonNull IMapItem map, + @NonNull Collection keys) { + Set keySet = keys.stream() + .map(IAnyAtomicItem::asMapKey) + .collect(Collectors.toSet()); + + Map remaining = ObjectUtils.notNull(map.entrySet().stream() + .filter(entry -> !keySet.contains(entry.getKey())) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))); + + return IMapItem.ofCollection(remaining); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapSize.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapSize.java new file mode 100644 index 000000000..6f9c6ffa3 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapSize.java @@ -0,0 +1,80 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.function.library; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.MetapathConstants; +import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils; +import gov.nist.secauto.metaschema.core.metapath.function.IArgument; +import gov.nist.secauto.metaschema.core.metapath.function.IFunction; +import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.metapath.item.atomic.IIntegerItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.IMapItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.List; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class MapSize { + @NonNull + static final IFunction SIGNATURE = IFunction.builder() + .name("size") + .namespace(MetapathConstants.NS_METAPATH_FUNCTIONS_MAP) + .deterministic() + .contextIndependent() + .focusIndependent() + .argument(IArgument.builder() + .name("map") + .type(IMapItem.class) + .one() + .build()) + .returnType(IIntegerItem.class) + .returnOne() + .functionHandler(MapSize::execute) + .build(); + + /** + * An implementation of XPath 3.1 map:size. + * + * @param array + * the arrays to join + * @return a new combined array + */ + @SuppressWarnings("unused") + @NonNull + private static ISequence execute(@NonNull IFunction function, + @NonNull List> arguments, + @NonNull DynamicContext dynamicContext, + IItem focus) { + IMapItem map = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0).getFirstItem(true))); + + return ISequence.of(IIntegerItem.valueOf(map.size())); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MpRecurseDepth.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MpRecurseDepth.java index 5e3e83139..d8bfdd423 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MpRecurseDepth.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MpRecurseDepth.java @@ -105,7 +105,7 @@ private static ISequence executeOneArg( ISequence initalContext = ISequence.of(FunctionUtils.requireType(INodeItem.class, focus)); ISequence arg = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0))); - IStringItem recursionPath = FunctionUtils.requireFirstItem(arg, true); + IStringItem recursionPath = ObjectUtils.requireNonNull(arg.getFirstItem(true)); return recurseDepth(initalContext, recursionPath, dynamicContext); } @@ -121,7 +121,7 @@ private static ISequence executeTwoArg( ISequence initalContext = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0))); ISequence arg = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(1))); - IStringItem recursionPath = FunctionUtils.requireFirstItem(arg, true); + IStringItem recursionPath = ObjectUtils.requireNonNull(arg.getFirstItem(true)); return recurseDepth(initalContext, recursionPath, dynamicContext); } @@ -162,12 +162,12 @@ public static ISequence recurseDepth( @NonNull MetapathExpression recursionMetapath, @NonNull DynamicContext dynamicContext) { - return ISequence.of(ObjectUtils.notNull(initialContext.asStream() + return ISequence.of(ObjectUtils.notNull(initialContext.stream() .flatMap(item -> { @NonNull ISequence metapathResult = recursionMetapath.evaluate(item, dynamicContext); ISequence result = recurseDepth(metapathResult, recursionMetapath, dynamicContext); - return ObjectUtils.notNull(Stream.concat(result.asStream(), Stream.of(item))); + return ObjectUtils.notNull(Stream.concat(result.stream(), Stream.of(item))); }))); } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/NumericFunction.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/NumericFunction.java index 09244ee9f..076bb9064 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/NumericFunction.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/NumericFunction.java @@ -63,6 +63,9 @@ static IFunction signature(@NonNull String namespace, @NonNull String name, @Non return IFunction.builder() .name(name) .namespace(namespace) + .deterministic() + .contextIndependent() + .focusIndependent() .argument(IArgument.builder() .name("arg1") .type(INumericItem.class) @@ -103,7 +106,7 @@ public ISequence execute(@NonNull IFunction function, return ISequence.empty(); // NOPMD - readability } - INumericItem item = FunctionUtils.getFirstItem(sequence, true); + INumericItem item = sequence.getFirstItem(true); if (item == null) { return ISequence.empty(); // NOPMD - readability } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractArrayItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractArrayItem.java new file mode 100644 index 000000000..dd6dd1b64 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractArrayItem.java @@ -0,0 +1,105 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.impl; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ICollectionValue; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils; +import gov.nist.secauto.metaschema.core.metapath.function.IArgument; +import gov.nist.secauto.metaschema.core.metapath.function.ISequenceType; +import gov.nist.secauto.metaschema.core.metapath.function.Occurrence; +import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem; +import gov.nist.secauto.metaschema.core.metapath.item.atomic.IIntegerItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.IArrayItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.EnumSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import javax.xml.namespace.QName; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public abstract class AbstractArrayItem + extends ImmutableCollections.AbstractImmutableDelegatedCollection + implements IArrayItem { + @NonNull + public static final QName QNAME = new QName("array"); + @NonNull + public static final Set PROPERTIES = ObjectUtils.notNull( + EnumSet.of(FunctionProperty.DETERMINISTIC)); + @NonNull + public static final List ARGUMENTS = ObjectUtils.notNull(List.of( + IArgument.builder().name("position").type(IIntegerItem.class).one().build())); + @NonNull + public static final ISequenceType RESULT = ISequenceType.of(IAnyAtomicItem.class, Occurrence.ZERO_OR_ONE); + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @NonNull + private static final IArrayItem EMPTY = new ArrayItemN<>(); + + @SuppressWarnings("unchecked") + @NonNull + public static IArrayItem empty() { + return (IArrayItem) EMPTY; + } + + @Override + public ISequence execute(List> arguments, DynamicContext dynamicContext, + ISequence focus) { + ISequence arg = FunctionUtils.asType( + ObjectUtils.notNull(arguments.get(0))); + + IIntegerItem position = arg.getFirstItem(true); + if (position == null) { + return ISequence.empty(); // NOPMD - readability + } + + int index = position.asInteger().intValueExact() - 1; + ICollectionValue result = getValue().get(index); + return result.asSequence(); + } + + @Override + public int hashCode() { + return Objects.hash(getValue()); + } + + @Override + public boolean equals(Object other) { + return other == this + || other instanceof IArrayItem && getValue().equals(((IArrayItem) other).getValue()); + } + + @Override + public String asString() { + return ObjectUtils.notNull(toString()); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractMapItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractMapItem.java new file mode 100644 index 000000000..41ab230cd --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractMapItem.java @@ -0,0 +1,105 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.impl; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ICollectionValue; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils; +import gov.nist.secauto.metaschema.core.metapath.function.IArgument; +import gov.nist.secauto.metaschema.core.metapath.function.ISequenceType; +import gov.nist.secauto.metaschema.core.metapath.function.Occurrence; +import gov.nist.secauto.metaschema.core.metapath.function.library.MapGet; +import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem; +import gov.nist.secauto.metaschema.core.metapath.item.atomic.IIntegerItem; +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.EnumSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +import javax.xml.namespace.QName; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public abstract class AbstractMapItem + extends ImmutableCollections.AbstractImmutableDelegatedMap + implements IMapItem { + @NonNull + public static final QName QNAME = new QName("map"); + @NonNull + public static final Set PROPERTIES = ObjectUtils.notNull( + EnumSet.of(FunctionProperty.DETERMINISTIC)); + @NonNull + public static final List ARGUMENTS = ObjectUtils.notNull(List.of( + IArgument.builder().name("key").type(IAnyAtomicItem.class).one().build())); + @NonNull + public static final ISequenceType RESULT = ISequenceType.of(IAnyAtomicItem.class, Occurrence.ZERO_OR_ONE); + + @NonNull + private static final IMapItem EMPTY = new MapItemN<>(); + + @SuppressWarnings("unchecked") + @NonNull + public static IMapItem empty() { + return (IMapItem) EMPTY; + } + + @Override + public ISequence execute(List> arguments, DynamicContext dynamicContext, + ISequence focus) { + ISequence arg = FunctionUtils.asType( + ObjectUtils.notNull(arguments.get(0))); + + IAnyAtomicItem key = arg.getFirstItem(true); + if (key == null) { + return ISequence.empty(); // NOPMD - readability + } + + ICollectionValue result = MapGet.get(this, key); + return result == null ? ISequence.empty() : result.asSequence(); + } + + @Override + public int hashCode() { + return Objects.hash(getValue()); + } + + @Override + public boolean equals(Object other) { + return other == this + || other instanceof IMapItem && getValue().equals(((IMapItem) other).getValue()); + } + + @Override + public String asString() { + return ObjectUtils.notNull(toString()); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/SingletonSequenceImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractSequence.java similarity index 66% rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/SingletonSequenceImpl.java rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractSequence.java index 2f5244aba..2d2a42783 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/SingletonSequenceImpl.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractSequence.java @@ -24,76 +24,51 @@ * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. */ -package gov.nist.secauto.metaschema.core.metapath; +package gov.nist.secauto.metaschema.core.metapath.impl; +import gov.nist.secauto.metaschema.core.metapath.ISequence; import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; -import java.util.List; -import java.util.function.Consumer; -import java.util.stream.Stream; +import java.util.stream.Collectors; import edu.umd.cs.findbugs.annotations.NonNull; -class SingletonSequenceImpl implements ISequence { - @NonNull - private final ITEM_TYPE item; - - public SingletonSequenceImpl(@NonNull ITEM_TYPE item) { - this.item = item; - } +public abstract class AbstractSequence + extends ImmutableCollections.AbstractImmutableDelegatedCollection + implements ISequence { + @SuppressWarnings({ "rawtypes", "unchecked" }) @NonNull - protected ITEM_TYPE getItem() { - return item; - } + private static final ISequence EMPTY = new SequenceN<>(); - @SuppressWarnings("null") - @Override - public List asList() { - return List.of(item); - } - - @SuppressWarnings("null") - @Override - public Stream asStream() { - return Stream.of(item); - } - - @Override - public boolean isEmpty() { - return false; - } - - @Override - public String toString() { - return asList().toString(); + @SuppressWarnings("unchecked") + public static ISequence empty() { + return (ISequence) EMPTY; } @Override - public int size() { - return 1; - } - - @Override - public ISequence collect() { - return this; + public boolean equals(Object other) { + // must either be the same instance or a sequence that has the same list + // contents + return other == this + || other instanceof ISequence && getValue().equals(((ISequence) other).getValue()); } @Override - public void forEach(Consumer action) { - action.accept(item); + public int hashCode() { + return getValue().hashCode(); } @Override - public boolean equals(Object other) { - // must either be the same instance or a sequence that has the same list - // contents - return other == this - || other instanceof ISequence && asList().equals(((ISequence) other).asList()); + public String asString() { + return ObjectUtils.notNull(toString()); } @Override - public int hashCode() { - return asList().hashCode(); + public String toString() { + return safeStream() + .map(Object::toString) + .collect(Collectors.joining(",", "(", ")")); } } diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/IInstanceModelChoiceBinding.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractStringMapKey.java similarity index 78% rename from databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/IInstanceModelChoiceBinding.java rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractStringMapKey.java index 7eeb41687..83bb7b822 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/IInstanceModelChoiceBinding.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractStringMapKey.java @@ -24,16 +24,22 @@ * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. */ -package gov.nist.secauto.metaschema.databind.model.metaschema; +package gov.nist.secauto.metaschema.core.metapath.impl; -import gov.nist.secauto.metaschema.core.model.IChoiceInstance; +import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey; -public interface IInstanceModelChoiceBinding - extends IBindingInstanceModelAbsolute, IChoiceInstance, IBindingContainerModelAbsolute { +public abstract class AbstractStringMapKey + implements IMapKey { @Override - IBindingDefinitionAssembly getOwningDefinition(); + public int hashCode() { + return getKey().asStringItem().hashCode(); + } @Override - IBindingDefinitionAssembly getContainingDefinition(); + public boolean equals(Object obj) { + return this == obj || + (obj instanceof AbstractStringMapKey + && getKey().asStringItem().equals(((AbstractStringMapKey) obj).getKey().asStringItem())); + } } diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/IBindingDefinitionModel.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/ArrayItemN.java similarity index 72% rename from databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/IBindingDefinitionModel.java rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/ArrayItemN.java index eb6bb5478..a700c5669 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/IBindingDefinitionModel.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/ArrayItemN.java @@ -24,29 +24,33 @@ * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. */ -package gov.nist.secauto.metaschema.databind.model.metaschema; +package gov.nist.secauto.metaschema.core.metapath.impl; -import gov.nist.secauto.metaschema.core.model.IModelDefinition; +import gov.nist.secauto.metaschema.core.metapath.ICollectionValue; +import gov.nist.secauto.metaschema.core.util.CollectionUtil; import gov.nist.secauto.metaschema.core.util.ObjectUtils; -import java.util.Collection; +import java.util.List; -import edu.umd.cs.findbugs.annotations.Nullable; +import edu.umd.cs.findbugs.annotations.NonNull; -public interface IBindingDefinitionModel - extends IBindingDefinition, IModelDefinition { - @Override - IBindingInstanceFlag getFlagInstanceByName(String name); +public class ArrayItemN + extends AbstractArrayItem { + @NonNull + private final List items; - @Override - Collection getFlagInstances(); + @SafeVarargs + public ArrayItemN(@NonNull ITEM... items) { + this(ObjectUtils.notNull(List.of(items))); + } - @Nullable - String getJsonKeyFlagName(); + public ArrayItemN(@NonNull List items) { + this.items = CollectionUtil.unmodifiableList(items); + } @Override - default IBindingInstanceFlag getJsonKeyFlagInstance() { - String name = getJsonKeyFlagName(); - return name == null ? null : ObjectUtils.requireNonNull(getFlagInstanceByName(name)); + public List getValue() { + return items; } + } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/ImmutableCollections.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/ImmutableCollections.java new file mode 100644 index 000000000..b56173120 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/ImmutableCollections.java @@ -0,0 +1,261 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.impl; + +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.AbstractCollection; +import java.util.AbstractMap; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Set; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Stream; + +import edu.umd.cs.findbugs.annotations.NonNull; + +/** + * This implementation is inspired by the similar implementation provided by the + * JDK. + */ +public final class ImmutableCollections { + + private ImmutableCollections() { + // disable construction + } + + private static UnsupportedOperationException unsupported() { + return new UnsupportedOperationException("method not supported"); + } + + public abstract static class AbstractImmutableCollection + extends AbstractCollection { + + @Override + public final boolean add(T item) { + throw unsupported(); + } + + @Override + public final boolean addAll(Collection collection) { + throw unsupported(); + } + + @Override + public final void clear() { + throw unsupported(); + } + + @Override + public final boolean remove(Object obj) { + throw unsupported(); + } + + @Override + public final boolean removeAll(Collection collection) { + throw unsupported(); + } + + @Override + public final boolean removeIf(Predicate filter) { + throw unsupported(); + } + + @Override + public final boolean retainAll(Collection collection) { + throw unsupported(); + } + } + + public abstract static class AbstractImmutableList + extends AbstractImmutableCollection + implements List { + + @Override + public boolean addAll(int index, Collection collection) { + throw unsupported(); + } + + @Override + public T set(int index, T element) { + throw unsupported(); + } + + @Override + public void add(int index, T element) { + throw unsupported(); + } + + @Override + public T remove(int index) { + throw unsupported(); + } + } + + public abstract static class AbstractImmutableDelegatedCollection + extends AbstractImmutableList { + + @NonNull + public abstract List getValue(); + + @Override + public T get(int index) { + return getValue().get(index); + } + + @Override + public int indexOf(Object obj) { + return getValue().indexOf(obj); + } + + @Override + public Iterator iterator() { + return getValue().iterator(); + } + + @Override + public int lastIndexOf(Object obj) { + return getValue().lastIndexOf(obj); + } + + @Override + public ListIterator listIterator() { + return getValue().listIterator(); + } + + @Override + public ListIterator listIterator(int index) { + return getValue().listIterator(index); + } + + @Override + public int size() { + return getValue().size(); + } + + @Override + public List subList(int fromIndex, int toIndex) { + return getValue().subList(fromIndex, toIndex); + } + + @Override + public Stream stream() { + return ObjectUtils.notNull(getValue().stream()); + } + + @Override + public String toString() { + return getValue().toString(); + } + } + + public abstract static class AbstractImmutableMap + extends AbstractMap { + @Override + public void clear() { + throw unsupported(); + } + + @Override + public V compute(K key, BiFunction rf) { + throw unsupported(); + } + + @Override + public V computeIfAbsent(K key, Function mf) { + throw unsupported(); + } + + @Override + public V computeIfPresent(K key, BiFunction rf) { + throw unsupported(); + } + + @Override + public V merge(K key, V value, BiFunction rf) { + throw unsupported(); + } + + @Override + public V put(K key, V value) { + throw unsupported(); + } + + @Override + public void putAll(Map map) { + throw unsupported(); + } + + @Override + public V putIfAbsent(K key, V value) { + throw unsupported(); + } + + @Override + public V remove(Object key) { + throw unsupported(); + } + + @Override + public boolean remove(Object key, Object value) { + throw unsupported(); + } + + @Override + public V replace(K key, V value) { + throw unsupported(); + } + + @Override + public boolean replace(K key, V oldValue, V newValue) { + throw unsupported(); + } + + @Override + public void replaceAll(BiFunction function) { + throw unsupported(); + } + } + + public abstract static class AbstractImmutableDelegatedMap + extends AbstractImmutableMap { + + @NonNull + public abstract Map getValue(); + + @Override + public Set> entrySet() { + return Collections.unmodifiableSet(getValue().entrySet()); + } + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/MapItemN.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/MapItemN.java new file mode 100644 index 000000000..0085a25b6 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/MapItemN.java @@ -0,0 +1,57 @@ +/* + * Portions of this software was developed by employees of the National Institute + * of Standards and Technology (NIST), an agency of the Federal Government and is + * being made available as a public service. Pursuant to title 17 United States + * Code Section 105, works of NIST employees are not subject to copyright + * protection in the United States. This software may be subject to foreign + * copyright. Permission in the United States and in foreign countries, to the + * extent that NIST may hold copyright, to use, copy, modify, create derivative + * works, and distribute this software and its documentation without fee is hereby + * granted on a non-exclusive basis, provided that this notice and disclaimer + * of warranty appears in all copies. + * + * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER + * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY + * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM + * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE + * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT + * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, + * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, + * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, + * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR + * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT + * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. + */ + +package gov.nist.secauto.metaschema.core.metapath.impl; + +import gov.nist.secauto.metaschema.core.metapath.ICollectionValue; +import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey; +import gov.nist.secauto.metaschema.core.util.CollectionUtil; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.Map; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class MapItemN + extends AbstractMapItem { + @NonNull + private final Map entries; + + @SafeVarargs + public MapItemN(@NonNull Map.Entry... entries) { + this(ObjectUtils.notNull(Map.ofEntries(entries))); + } + + public MapItemN(@NonNull Map entries) { + + this.entries = CollectionUtil.unmodifiableMap(entries); + } + + @Override + public Map getValue() { + return entries; + } +} diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/impl/IFeatureBoundContainerFlag.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/SequenceN.java similarity index 65% rename from databind/src/main/java/gov/nist/secauto/metaschema/databind/model/impl/IFeatureBoundContainerFlag.java rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/SequenceN.java index e5d2f7976..618c0a50b 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/impl/IFeatureBoundContainerFlag.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/SequenceN.java @@ -24,40 +24,43 @@ * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. */ -package gov.nist.secauto.metaschema.databind.model.impl; +package gov.nist.secauto.metaschema.core.metapath.impl; -import gov.nist.secauto.metaschema.core.model.IContainerFlagSupport; -import gov.nist.secauto.metaschema.core.model.IFeatureContainerFlag; +import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.util.CollectionUtil; import gov.nist.secauto.metaschema.core.util.ObjectUtils; -import gov.nist.secauto.metaschema.databind.model.IBoundContainerFlag; -import gov.nist.secauto.metaschema.databind.model.IBoundInstanceFlag; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; import edu.umd.cs.findbugs.annotations.NonNull; -import edu.umd.cs.findbugs.annotations.Nullable; -/** - * Provides default implementations based on a supporting glag container - * implementation. - */ -public interface IFeatureBoundContainerFlag - extends IBoundContainerFlag, - IFeatureContainerFlag { - - @Override +public class SequenceN + extends AbstractSequence { @NonNull - IContainerFlagSupport getFlagContainer(); + private final List items; - @Override - @Nullable - default IBoundInstanceFlag getFlagInstanceByName(String name) { - return getFlagContainer().getFlagInstanceMap().get(name); + public SequenceN(@NonNull Collection items) { + this(new ArrayList<>(items), false); + } + + public SequenceN(@NonNull List items, boolean copy) { + this.items = CollectionUtil.unmodifiableList(copy ? new ArrayList<>(items) : items); + } + + @SafeVarargs + public SequenceN(@NonNull ITEM... items) { + this(CollectionUtil.unmodifiableList(ObjectUtils.notNull(List.of(items)))); + } + + public SequenceN(@NonNull List items) { + this.items = items; } @Override - @NonNull - default Collection getFlagInstances() { - return ObjectUtils.notNull(getFlagContainer().getFlagInstanceMap().values()); + public List getValue() { + return items; } + } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/EmptyListImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/SingletonSequence.java similarity index 73% rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/EmptyListImpl.java rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/SingletonSequence.java index 56e2bfbe4..4c4356188 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/EmptyListImpl.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/SingletonSequence.java @@ -24,58 +24,55 @@ * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. */ -package gov.nist.secauto.metaschema.core.metapath; +package gov.nist.secauto.metaschema.core.metapath.impl; import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.util.CollectionUtil; -import java.util.Collections; import java.util.List; import java.util.function.Consumer; import java.util.stream.Stream; -class EmptyListImpl implements ISequence { +import edu.umd.cs.findbugs.annotations.NonNull; - @SuppressWarnings("null") - @Override - public List asList() { - return Collections.emptyList(); - } +public class SingletonSequence + extends AbstractSequence { + @NonNull + private final ITEM item; - @SuppressWarnings("null") - @Override - public Stream asStream() { - return Stream.empty(); + public SingletonSequence(@NonNull ITEM item) { + this.item = item; } - @Override - public boolean isEmpty() { - return true; + @NonNull + protected ITEM getItem() { + return item; } + @SuppressWarnings("null") @Override - public int size() { - return 0; + public List getValue() { + return CollectionUtil.singletonList(item); } @Override - public ISequence collect() { - return this; + public boolean isEmpty() { + return false; } @Override - public void forEach(Consumer action) { - // do nothing + public int size() { + return 1; } + @SuppressWarnings("null") @Override - public boolean equals(Object other) { - // must either be the same instance or a sequence that is empty - return other == this - || other instanceof ISequence && ((ISequence) other).isEmpty(); + public Stream stream() { + return Stream.of(item); } @Override - public int hashCode() { - return 1; + public void forEach(Consumer action) { + action.accept(item); } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/StreamSequenceImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/StreamSequence.java similarity index 68% rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/StreamSequenceImpl.java rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/StreamSequence.java index 184cf4acb..d4c840bfd 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/StreamSequenceImpl.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/StreamSequence.java @@ -24,7 +24,7 @@ * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. */ -package gov.nist.secauto.metaschema.core.metapath; +package gov.nist.secauto.metaschema.core.metapath.impl; import gov.nist.secauto.metaschema.core.metapath.item.IItem; import gov.nist.secauto.metaschema.core.util.ObjectUtils; @@ -37,25 +37,22 @@ import edu.umd.cs.findbugs.annotations.NonNull; -class StreamSequenceImpl implements ISequence { - private Stream stream; - private List list; +public class StreamSequence + extends AbstractSequence { - public StreamSequenceImpl(@NonNull Stream stream) { + private Stream stream; + private List list; + + public StreamSequence(@NonNull Stream stream) { Objects.requireNonNull(stream, "stream"); this.stream = stream; } @Override - public boolean isEmpty() { - return asList().isEmpty(); - } - - @Override - public List asList() { + public List getValue() { synchronized (this) { if (list == null) { - list = asStream().collect(Collectors.toUnmodifiableList()); + list = stream().collect(Collectors.toUnmodifiableList()); } assert list != null; return list; @@ -63,8 +60,9 @@ public List asList() { } @Override - public Stream asStream() { - @NonNull Stream retval; + public Stream stream() { + @NonNull Stream retval; + // Ensure thread safety and prevent multiple consumptions of the stream synchronized (this) { if (list == null) { if (stream == null) { @@ -81,36 +79,7 @@ public Stream asStream() { } @Override - public void forEach(Consumer action) { - asStream().forEachOrdered(action); - } - - @Override - public String toString() { - return asList().toString(); - } - - @Override - public int size() { - return asList().size(); - } - - @Override - public ISequence collect() { - asList(); - return this; - } - - @Override - public boolean equals(Object other) { - // must either be the same instance or a sequence that has the same list - // contents - return other == this - || other instanceof ISequence && asList().equals(((ISequence) other).asList()); - } - - @Override - public int hashCode() { - return asList().hashCode(); + public void forEach(Consumer action) { + stream().forEachOrdered(action); } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/IItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/IItem.java index b1ea60637..92c4f4df8 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/IItem.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/IItem.java @@ -27,8 +27,13 @@ package gov.nist.secauto.metaschema.core.metapath.item; import gov.nist.secauto.metaschema.core.datatype.IDataTypeAdapter; +import gov.nist.secauto.metaschema.core.metapath.ICollectionValue; +import gov.nist.secauto.metaschema.core.metapath.ISequence; + +import java.util.stream.Stream; + +public interface IItem extends ICollectionValue { -public interface IItem { /** * Get the item's "wrapped" value. This "wrapped" value may be: *