From 0235e9a88469555c8a6e507e20ccd1cec55e9346 Mon Sep 17 00:00:00 2001 From: David Waltermire Date: Fri, 31 May 2024 11:50:18 -0400 Subject: [PATCH] This PR adds the following new Metapath map features. - Support for map construction. - Added support for maps in function call, postfix and unary lookups. - Added support and unit tests for the following Metapath functions: - map:get - map:merge - map:entry - map:size - map:keys - map:contains - map:find - map:put - map:remove - Added missing characteristics on a number of existing Metapath functions. - Cleaned up a bunch of PMD warnings. --- core/src/main/antlr4/Metapath10.g4 | 17 +- core/src/main/antlr4/Metapath10Lexer.g4 | 298 +++---- .../flexmark/impl/AbstractMarkupWriter.java | 3 +- .../core/metapath/ICollectionValue.java | 4 +- .../{IStringValued.java => IPrintable.java} | 2 +- .../metaschema/core/metapath/ISequence.java | 45 +- .../InvalidTypeMetapathException.java | 8 +- .../core/metapath/MetapathConstants.java | 5 + .../core/metapath/MetapathExpression.java | 9 + .../core/metapath/StaticContext.java | 3 + .../metapath/antlr/AbstractAstVisitor.java | 226 +++--- .../metapath/cst/AbstractCSTVisitorBase.java | 14 +- .../cst/AbstractExpressionVisitor.java | 16 +- .../core/metapath/cst/AbstractLookup.java | 69 +- ...nce.java => ArraySequenceConstructor.java} | 4 +- ...quare.java => ArraySquareConstructor.java} | 7 +- .../core/metapath/cst/BuildCSTVisitor.java | 56 +- .../core/metapath/cst/CSTPrinter.java | 14 +- .../metapath/cst/FunctionCallAccessor.java | 24 +- .../core/metapath/cst/IExpressionVisitor.java | 27 +- .../core/metapath/cst/MapConstructor.java | 114 +++ .../metapath/function/DefaultFunction.java | 2 +- .../InvalidValueForCastFunctionException.java | 6 +- .../function/JsonFunctionException.java | 98 +++ .../function/library/ArrayAppend.java | 11 +- .../function/library/ArrayFlatten.java | 9 +- .../metapath/function/library/ArrayGet.java | 16 +- .../metapath/function/library/ArrayHead.java | 9 +- .../function/library/ArrayInsertBefore.java | 11 +- .../metapath/function/library/ArrayJoin.java | 11 +- .../metapath/function/library/ArrayPut.java | 11 +- .../function/library/ArrayRemove.java | 15 +- .../function/library/ArrayReverse.java | 9 +- .../metapath/function/library/ArraySize.java | 3 + .../function/library/ArraySubarray.java | 12 +- .../metapath/function/library/ArrayTail.java | 9 +- .../function/library/CastFunction.java | 3 + .../library/DefaultFunctionLibrary.java | 21 + .../function/library/FnStartsWith.java | 3 + .../function/library/FnStaticBaseUri.java | 3 + .../function/library/MapContains.java | 102 +++ .../metapath/function/library/MapEntry.java | 102 +++ .../metapath/function/library/MapFind.java | 157 ++++ .../metapath/function/library/MapGet.java | 104 +++ .../metapath/function/library/MapKeys.java | 96 +++ .../metapath/function/library/MapMerge.java | 226 ++++++ .../metapath/function/library/MapPut.java | 117 +++ .../metapath/function/library/MapRemove.java | 115 +++ .../metapath/function/library/MapSize.java | 80 ++ .../function/library/NumericFunction.java | 3 + .../core/metapath/impl/AbstractMapItem.java | 105 +++ .../metapath/impl/AbstractStringMapKey.java | 45 ++ .../metapath/impl/ImmutableCollections.java | 113 ++- .../core/metapath/impl/MapItemN.java | 57 ++ .../item/atomic/AbstractDateItem.java | 7 +- .../item/atomic/AbstractDateTimeItem.java | 7 +- .../item/atomic/AbstractDecimalItem.java | 66 ++ .../item/atomic/AbstractIntegerItem.java | 2 +- .../item/atomic/AbstractStringItem.java | 17 + .../item/atomic/AbstractTemporalItem.java | 74 ++ .../atomic/AbstractUntypedAtomicItem.java | 55 ++ .../metapath/item/atomic/AbstractUriItem.java | 17 + .../item/atomic/Base64BinaryItemImpl.java | 25 + .../metapath/item/atomic/BooleanItemImpl.java | 25 + .../item/atomic/DayTimeDurationItemImpl.java | 25 + .../metapath/item/atomic/DecimalItemImpl.java | 3 +- .../metapath/item/atomic/IAnyAtomicItem.java | 8 +- .../metapath/item/atomic/IAnyUriItem.java | 2 +- .../metapath/item/atomic/IIPAddressItem.java | 3 - .../item/atomic/IPv4AddressItemImpl.java | 2 +- .../item/atomic/IPv6AddressItemImpl.java | 2 +- .../metapath/item/atomic/ITemporalItem.java | 31 + .../item/atomic/MarkupLineItemImpl.java | 2 +- .../item/atomic/MarkupMultiLineItemImpl.java | 2 +- .../metapath/item/atomic/UuidItemImpl.java | 25 + .../atomic/YearMonthDurationItemImpl.java | 25 + .../metapath/item/function/IArrayItem.java | 38 +- .../core/metapath/item/function/IMapItem.java | 756 ++++++++++++++++++ .../core/metapath/item/function/IMapKey.java | 43 + .../AbstractGlobalAssemblyDefinition.java | 2 +- .../model/AbstractGlobalFieldDefinition.java | 2 +- .../model/AbstractGlobalFlagDefinition.java | 2 +- .../core/model/FlagContainerBuilder.java | 2 +- .../core/model/xml/impl/XmlFieldInstance.java | 2 +- .../core/model/xml/impl/XmlFlagInstance.java | 2 +- .../xml/impl/XmlGlobalAssemblyDefinition.java | 3 +- .../xml/impl/XmlGlobalFieldDefinition.java | 3 +- .../xml/impl/XmlGlobalFlagDefinition.java | 3 +- .../xml/impl/XmlInlineFlagDefinition.java | 3 +- core/src/main/java/module-info.java | 29 +- .../metaschema/core/metapath/TestUtils.java | 17 + .../function/library/MapContainsTest.java | 74 ++ .../function/library/MapEntryTest.java | 65 ++ .../function/library/MapFindTest.java | 80 ++ .../metapath/function/library/MapGetTest.java | 70 ++ .../function/library/MapKeysTest.java | 57 ++ .../function/library/MapMergeTest.java | 113 +++ .../metapath/function/library/MapPutTest.java | 85 ++ .../function/library/MapRemoveTest.java | 101 +++ .../function/library/MapSizeTest.java | 65 ++ .../item/function/IArrayItemTest.java | 79 -- .../metapath/item/function/LookupTest.java | 183 +++++ .../annotations/NullJavaTypeAdapter.java | 6 + 103 files changed, 4453 insertions(+), 506 deletions(-) rename core/src/main/java/gov/nist/secauto/metaschema/core/metapath/{IStringValued.java => IPrintable.java} (98%) rename core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/{ArraySequence.java => ArraySequenceConstructor.java} (95%) rename core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/{ArraySquare.java => ArraySquareConstructor.java} (93%) create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/MapConstructor.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/JsonFunctionException.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapContains.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapEntry.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapFind.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapGet.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapKeys.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapMerge.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapPut.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapRemove.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapSize.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractMapItem.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractStringMapKey.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/MapItemN.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractDecimalItem.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractTemporalItem.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractUntypedAtomicItem.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/ITemporalItem.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/function/IMapItem.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/function/IMapKey.java create mode 100644 core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapContainsTest.java create mode 100644 core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapEntryTest.java create mode 100644 core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapFindTest.java create mode 100644 core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapGetTest.java create mode 100644 core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapKeysTest.java create mode 100644 core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapMergeTest.java create mode 100644 core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapPutTest.java create mode 100644 core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapRemoveTest.java create mode 100644 core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapSizeTest.java create mode 100644 core/src/test/java/gov/nist/secauto/metaschema/core/metapath/item/function/LookupTest.java diff --git a/core/src/main/antlr4/Metapath10.g4 b/core/src/main/antlr4/Metapath10.g4 index acea52be3..0fb07f3ca 100644 --- a/core/src/main/antlr4/Metapath10.g4 +++ b/core/src/main/antlr4/Metapath10.g4 @@ -4,11 +4,8 @@ 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 ; @@ -81,7 +78,7 @@ keyspecifier : NCName | IntegerLiteral | parenthesizedexpr | STAR ; //arrowfunctionspecifier : eqname | varref | parenthesizedexpr ; arrowfunctionspecifier : eqname; // primaryexpr : literal | varref | parenthesizedexpr | contextitemexpr | functioncall | functionitemexpr | mapconstructor | arrayconstructor | unarylookup ; -primaryexpr : literal | varref | parenthesizedexpr | contextitemexpr | functioncall | arrayconstructor | unarylookup; +primaryexpr : literal | varref | parenthesizedexpr | contextitemexpr | functioncall | mapconstructor | arrayconstructor | unarylookup; literal : numericliteral | StringLiteral ; numericliteral : IntegerLiteral | DecimalLiteral | DoubleLiteral ; varref : DOLLAR varname ; @@ -97,11 +94,11 @@ 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 ; +mapconstructorentry : mapkeyexpr COLON mapvalueexpr ; +mapkeyexpr : exprsingle ; +mapvalueexpr : exprsingle ; arrayconstructor : squarearrayconstructor | curlyarrayconstructor ; squarearrayconstructor : OB (exprsingle ( COMMA exprsingle)*)? CB ; // [75] @@ -152,7 +149,7 @@ unarylookup : QM keyspecifier ; // 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/markup/flexmark/impl/AbstractMarkupWriter.java b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/AbstractMarkupWriter.java index 49ef7c5a9..97ce2f32b 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/AbstractMarkupWriter.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/datatype/markup/flexmark/impl/AbstractMarkupWriter.java @@ -63,9 +63,8 @@ import com.vladsch.flexmark.util.sequence.BasedSequence; import com.vladsch.flexmark.util.sequence.Escaping; -import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.IMarkupWriter; import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.HtmlQuoteTagExtension.DoubleQuoteNode; -import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.IMarkupWriter.ChildHandler; +import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.IMarkupWriter; import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.InsertAnchorExtension.InsertAnchorNode; import gov.nist.secauto.metaschema.core.util.CollectionUtil; import gov.nist.secauto.metaschema.core.util.ObjectUtils; diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/ICollectionValue.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/ICollectionValue.java index 1293ee9aa..58520adcc 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/ICollectionValue.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/ICollectionValue.java @@ -40,7 +40,9 @@ public interface ICollectionValue { @NonNull static Stream normalizeAsItems(@NonNull ICollectionValue value) { - return value instanceof IItem ? ObjectUtils.notNull(Stream.of((IItem) value)) : value.asSequence().stream(); + return value instanceof IItem + ? ObjectUtils.notNull(Stream.of((IItem) value)) + : value.asSequence().stream(); } @NonNull diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/IStringValued.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/IPrintable.java similarity index 98% rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/IStringValued.java rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/IPrintable.java index ec9b682db..0cae7cbcc 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/IStringValued.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/IPrintable.java @@ -28,7 +28,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; -public interface IStringValued { +public interface IPrintable { /** * Get the string value. * 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 b93b84050..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 @@ -60,7 +60,7 @@ * the Java type of the items in a sequence */ @SuppressWarnings("PMD.ShortMethodName") -public interface ISequence extends List, IStringValued, ICollectionValue { +public interface ISequence extends List, IPrintable, ICollectionValue { /** * Get an empty sequence. * @@ -154,11 +154,11 @@ default ITEM getFirstItem(boolean requireSingleton) { } @NonNull - default ICollectionValue toArrayMember() { + default ICollectionValue toCollectionValue() { ICollectionValue retval; switch (size()) { case 0: - retval = ISequence.empty(); + retval = empty(); break; case 1: retval = ObjectUtils.notNull(stream().findFirst().get()); @@ -254,23 +254,6 @@ static ISequence map( .collect(toSequence()); } - /** - * 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); - } - /** * Returns an unmodifiable sequence containing the provided {@code items}. * @@ -294,6 +277,23 @@ static ISequence ofCollection( // NOPMD - i return retval; } + /** + * 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); + } + /** * Returns an unmodifiable sequence containing the provided {@code items}. * @@ -305,9 +305,8 @@ static ISequence ofCollection( // NOPMD - i */ // TODO: remove null check on callers @NonNull - static ISequence of( // NOPMD - intentional - Stream items) { - return items == null ? empty() : new StreamSequence<>(items); + static ISequence of(@NonNull Stream items) { + return new StreamSequence<>(items); } /** 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 115c0f63a..aa76b984b 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 @@ -55,6 +55,9 @@ public final class MetapathConstants { public static final URI NS_METAPATH_FUNCTIONS_ARRAY = ObjectUtils.requireNonNull( URI.create("http://csrc.nist.gov/ns/metaschema/metapath-functions/array")); @NonNull + public static final URI NS_METAPATH_FUNCTIONS_MAP = ObjectUtils.requireNonNull( + URI.create("http://csrc.nist.gov/ns/metaschema/metapath-functions/map")); + @NonNull public static final URI NS_METAPATH_FUNCTIONS_EXTENDED = NS_METAPATH; @NonNull @@ -67,6 +70,8 @@ public final class MetapathConstants { 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 1e8b7ca17..9054e741a 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; @@ -145,6 +147,13 @@ public static MetapathExpression compile(@NonNull String path, @NonNull StaticCo 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()); 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 1859059a7..9356bc5fd 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 @@ -65,6 +65,9 @@ public final class StaticContext { 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); } 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 b00d13711..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 @@ -54,6 +54,10 @@ 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; @@ -145,11 +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) { @@ -177,11 +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) { @@ -189,11 +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. @@ -225,11 +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. @@ -252,13 +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. @@ -276,13 +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. @@ -340,11 +331,9 @@ public R visitEnclosedexpr(EnclosedexprContext ctx) { return expr == null ? null : expr.accept(this); } - /* - * ========================================================================= - * Filter Expressions - https://www.w3.org/TR/xpath-31/#id-filter-expression - * ========================================================================= - */ + // ========================================================================= + // Filter Expressions - https://www.w3.org/TR/xpath-31/#id-filter-expression + // ========================================================================= /** * Handle the provided expression. @@ -391,11 +380,9 @@ public R visitLookup(LookupContext ctx) { return handleLookup(ctx); } - /* - * ====================================================================== Path - * Expressions - https://www.w3.org/TR/xpath-31/#id-path-expressions - * ====================================================================== - */ + // ====================================================================== + // Path Expressions - https://www.w3.org/TR/xpath-31/#id-path-expressions + // ====================================================================== /** * Handle the provided expression. @@ -412,13 +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. @@ -435,11 +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) { @@ -479,11 +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. @@ -506,11 +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) { @@ -524,11 +502,9 @@ 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) { @@ -563,11 +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. @@ -599,11 +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. @@ -620,11 +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. @@ -656,11 +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. @@ -713,13 +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. @@ -736,11 +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. @@ -769,11 +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. @@ -867,6 +828,43 @@ public R visitSimpleletbinding(SimpleletbindingContext ctx) { throw new IllegalStateException(); } + // ====================================================================== + // 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 // ============================================================== @@ -886,12 +884,6 @@ public R visitArrayconstructor(ArrayconstructorContext ctx) { */ protected abstract R handleArrayConstructor(@NonNull SquarearrayconstructorContext ctx); - @Override - public R visitSquarearrayconstructor(SquarearrayconstructorContext ctx) { - assert ctx != null; - return handleArrayConstructor(ctx); - } - /** * Handle the provided expression. * @@ -901,6 +893,12 @@ public R visitSquarearrayconstructor(SquarearrayconstructorContext ctx) { */ 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; 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 cf9dd621d..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 @@ -132,20 +132,20 @@ public IExpression visit(ParseTree tree) { } @Nullable - protected IExpression - nAiryToCollection( + protected + R nairyToCollection( @NonNull CONTEXT context, int startIndex, int step, - @NonNull BiFunction parser, - @NonNull Function, IExpression> supplier) { + @NonNull BiFunction parser, + @NonNull Function, R> supplier) { int numChildren = context.getChildCount(); - IExpression retval = null; + R retval = null; if (startIndex < numChildren) { - List children = new ArrayList<>((numChildren - startIndex) / step); + List children = new ArrayList<>((numChildren - startIndex) / step); for (int idx = startIndex; idx < numChildren; idx += step) { - EXPRESSION result = parser.apply(context, idx); + T result = parser.apply(context, idx); children.add(result); } retval = supplier.apply(children); 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 9708e7542..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 @@ -58,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 { /** @@ -354,12 +354,22 @@ public RESULT visitSimpleMap(SimpleMap expr, CONTEXT context) { } @Override - public RESULT visitArray(ArraySequence expr, CONTEXT context) { + public RESULT visitMapConstructor(MapConstructor expr, CONTEXT context) { return visitChildren(expr, context); } @Override - public RESULT visitArray(ArraySquare expr, CONTEXT context) { + 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); } 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 index e61f89fed..5bb77d4b5 100644 --- 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 @@ -30,12 +30,17 @@ 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; @@ -63,6 +68,8 @@ default Stream lookup( 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())); @@ -70,10 +77,17 @@ default Stream lookup( 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 { @@ -96,13 +110,21 @@ public Stream lookupInArray( 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() - 1; + index = literal.asInteger().intValueExact(); } @Override @@ -111,7 +133,7 @@ public Stream lookupInArray( DynamicContext dynamicContext, ISequence focus) { try { - return Stream.of(item.get(index)); + return ObjectUtils.notNull(Stream.ofNullable(ArrayGet.get(item, index))); } catch (IndexOutOfBoundsException ex) { throw new ArrayException( ArrayException.INDEX_OUT_OF_BOUNDS, @@ -121,6 +143,14 @@ public Stream lookupInArray( 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 { @@ -130,7 +160,15 @@ public Stream lookupInArray( IArrayItem item, DynamicContext dynamicContext, ISequence focus) { - return item.stream(); + return ObjectUtils.notNull(item.stream()); + } + + @Override + public Stream lookupInMap( + IMapItem item, + DynamicContext dynamicContext, + ISequence focus) { + return ObjectUtils.notNull(item.values().stream()); } } @@ -147,18 +185,18 @@ public IExpression getKeyExpression() { } @Override - public Stream lookupInArray( + public Stream lookupInArray( IArrayItem item, DynamicContext dynamicContext, ISequence focus) { ISequence keys = FnData.fnData(getKeyExpression().accept(dynamicContext, focus)); - return keys.stream() - .map(key -> { + return ObjectUtils.notNull(keys.stream() + .flatMap(key -> { if (key instanceof IIntegerItem) { - int index = ((IIntegerItem) key).asInteger().intValueExact() - 1; + int index = ((IIntegerItem) key).asInteger().intValueExact(); try { - return item.get(index); + return Stream.ofNullable(ArrayGet.get(item, index)); } catch (IndexOutOfBoundsException ex) { throw new ArrayException( ArrayException.INDEX_OUT_OF_BOUNDS, @@ -173,8 +211,21 @@ public Stream lookupInArray( 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/ArraySequence.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ArraySequenceConstructor.java similarity index 95% rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ArraySequence.java rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ArraySequenceConstructor.java index cdf18b221..6b837b524 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ArraySequence.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ArraySequenceConstructor.java @@ -34,11 +34,11 @@ import edu.umd.cs.findbugs.annotations.Nullable; -public class ArraySequence implements IExpression { +public class ArraySequenceConstructor implements IExpression { @Nullable private final IExpression expr; - public ArraySequence(@Nullable IExpression expr) { + public ArraySequenceConstructor(@Nullable IExpression expr) { this.expr = expr; } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ArraySquare.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ArraySquareConstructor.java similarity index 93% rename from core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ArraySquare.java rename to core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ArraySquareConstructor.java index 35dd54ef0..6a98a508a 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ArraySquare.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/ArraySquareConstructor.java @@ -35,11 +35,11 @@ import edu.umd.cs.findbugs.annotations.NonNull; -public class ArraySquare implements IExpression { +public class ArraySquareConstructor implements IExpression { @NonNull private final List children; - public ArraySquare(@NonNull List children) { + public ArraySquareConstructor(@NonNull List children) { this.children = children; } @@ -52,7 +52,7 @@ public List getChildren() { public ISequence accept(DynamicContext dynamicContext, ISequence focus) { return ISequence.of(getChildren().stream() .map(expr -> expr.accept(dynamicContext, focus)) - .map(ISequence::toArrayMember) + .map(ISequence::toCollectionValue) .collect(IArrayItem.toArrayItem())); } @@ -60,5 +60,4 @@ public ISequence accept(DynamicContext dynamicContext, ISequenc 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 2f3f254dd..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 @@ -52,6 +52,8 @@ 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; @@ -265,32 +267,54 @@ protected IExpression handleLet(LetexprContext context) { 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) { - if (context.getChildCount() == 2) { - // empty - return new ArraySquare(CollectionUtil.emptyList()); - } - - return 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 ArraySquare(children); - }); + 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 ArraySequence(visit(ctx.enclosedexpr())); + return new ArraySequenceConstructor(visit(ctx.enclosedexpr())); } // =============================================== 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 44a842c47..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 @@ -66,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 { @@ -337,12 +338,12 @@ public String visitSimpleMap(SimpleMap expr, State context) { } @Override - public String visitArray(ArraySequence expr, State context) { + public String visitArray(ArraySequenceConstructor expr, State context) { return appendNode(expr, super.visitArray(expr, context), context); } @Override - public String visitArray(ArraySquare expr, State context) { + public String visitArray(ArraySquareConstructor expr, State context) { return appendNode(expr, super.visitArray(expr, context), context); } @@ -361,6 +362,15 @@ 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/FunctionCallAccessor.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/cst/FunctionCallAccessor.java index 39b2213b7..d019f292a 100644 --- 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 @@ -27,10 +27,16 @@ 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.util.ObjectUtils; +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; @@ -75,10 +81,20 @@ public List getChildren() { @Override public ISequence accept(DynamicContext dynamicContext, ISequence focus) { - ISequence collection = getBase().accept(dynamicContext, focus); - ISequence key = getArgument().accept(dynamicContext, focus); + ISequence target = getBase().accept(dynamicContext, focus); + IItem collection = target.getFirstItem(true); + IAnyAtomicItem key = FnData.fnData(getArgument().accept(dynamicContext, focus)).getFirstItem(false); - return ArrayGet.SIGNATURE.execute(ObjectUtils.notNull(List.of(collection, key)), dynamicContext, focus); + 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 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 633120ab1..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 @@ -58,6 +58,7 @@ * @param * additional state to pass between nodes visited */ +@SuppressWarnings("PMD.ExcessivePublicCount") public interface IExpressionVisitor { /** @@ -520,7 +521,7 @@ public interface IExpressionVisitor { * the processing context * @return the visitation result or {@code null} if no result was produced */ - RESULT visitArray(@NonNull ArraySequence expr, @NonNull CONTEXT context); + RESULT visitMapConstructor(@NonNull MapConstructor expr, @NonNull CONTEXT context); /** * Visit the CST node. @@ -531,7 +532,29 @@ public interface IExpressionVisitor { * the processing context * @return the visitation result or {@code null} if no result was produced */ - RESULT visitArray(@NonNull ArraySquare expr, @NonNull CONTEXT context); + 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. 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/function/DefaultFunction.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/DefaultFunction.java index 27690d589..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 @@ -284,7 +284,7 @@ protected static ISequence convertSequence(@NonNull IArgument argument, @NonN Stream stream = sequence.safeStream(); if (IAnyAtomicItem.class.isAssignableFrom(requiredSequenceTypeClass)) { - Stream atomicStream = stream.flatMap(item -> FnData.atomize(item)); + Stream atomicStream = stream.flatMap(FnData::atomize); // if (IUntypedAtomicItem.class.isInstance(item)) { // NOPMD // // TODO: apply cast to atomic type 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/library/ArrayAppend.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/ArrayAppend.java index e1ad07b69..c3ac3a69c 100644 --- 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 @@ -42,11 +42,14 @@ import edu.umd.cs.findbugs.annotations.NonNull; -public class ArrayAppend { +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) @@ -62,6 +65,10 @@ public class ArrayAppend { .functionHandler(ArrayAppend::execute) .build(); + private ArrayAppend() { + // disable construction + } + @SuppressWarnings("unused") @NonNull private static ISequence> execute(@NonNull IFunction function, @@ -70,7 +77,7 @@ private static ISequence> execute(@No IItem focus) { IArrayItem array = FunctionUtils.asType(ObjectUtils.requireNonNull( arguments.get(0).getFirstItem(true))); - @SuppressWarnings("unchecked") T appendage = (T) arguments.get(1).toArrayMember(); + @SuppressWarnings("unchecked") T appendage = (T) arguments.get(1).toCollectionValue(); return ISequence.of(append(array, appendage)); } 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 index 0ced0bf9c..ca0059262 100644 --- 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 @@ -40,11 +40,14 @@ import edu.umd.cs.findbugs.annotations.NonNull; -public class ArrayFlatten { +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) @@ -55,6 +58,10 @@ public class ArrayFlatten { .functionHandler(ArrayFlatten::execute) .build(); + private ArrayFlatten() { + // disable construction + } + @SuppressWarnings("unused") @NonNull private static ISequence execute(@NonNull IFunction function, 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 index 680b3e6df..8aa5d49be 100644 --- 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 @@ -43,11 +43,14 @@ import edu.umd.cs.findbugs.annotations.NonNull; -public class ArrayGet { +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) @@ -63,6 +66,10 @@ public class ArrayGet { .functionHandler(ArrayGet::execute) .build(); + private ArrayGet() { + // disable construction + } + @SuppressWarnings("unused") @NonNull private static ISequence execute(@NonNull IFunction function, @@ -93,8 +100,13 @@ private static ISequence execute(@NonNull IFunction function, public static T get( @NonNull List target, @NonNull IIntegerItem positionItem) { - int position = positionItem.asInteger().intValue(); + 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) { 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 index af5a4ba9a..ac5f1d285 100644 --- 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 @@ -42,11 +42,14 @@ import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; -public class ArrayHead { +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) @@ -57,6 +60,10 @@ public class ArrayHead { .functionHandler(ArrayHead::execute) .build(); + private ArrayHead() { + // disable construction + } + @SuppressWarnings("unused") @NonNull private static ISequence execute(@NonNull IFunction function, 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 index a2f3cea92..3d7807396 100644 --- 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 @@ -43,11 +43,14 @@ import edu.umd.cs.findbugs.annotations.NonNull; -public class ArrayInsertBefore { +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) @@ -68,6 +71,10 @@ public class ArrayInsertBefore { .functionHandler(ArrayInsertBefore::execute) .build(); + private ArrayInsertBefore() { + // disable construction + } + @SuppressWarnings("unused") @NonNull private static ISequence> execute(@NonNull IFunction function, @@ -77,7 +84,7 @@ private static ISequence> execute(@No 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)).toArrayMember(); + @SuppressWarnings("unchecked") T member = (T) ObjectUtils.requireNonNull(arguments.get(2)).toCollectionValue(); return ISequence.of(insertBefore(array, position, member)); } 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 index ffe8ced15..d8d7aa7a3 100644 --- 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 @@ -43,11 +43,14 @@ import edu.umd.cs.findbugs.annotations.NonNull; -public class ArrayJoin { +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) @@ -58,6 +61,10 @@ public class ArrayJoin { .functionHandler(ArrayJoin::execute) .build(); + private ArrayJoin() { + // disable construction + } + @SuppressWarnings("unused") @NonNull private static ISequence> execute(@NonNull IFunction function, @@ -83,7 +90,7 @@ private static ISequence> e public static IArrayItem join( @NonNull Collection> arrays) { return IArrayItem.ofCollection(ObjectUtils.notNull(arrays.stream() - .flatMap(array -> array.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 index cea736e1e..e84f7cc93 100644 --- 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 @@ -44,11 +44,14 @@ import edu.umd.cs.findbugs.annotations.NonNull; -public class ArrayPut { +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) @@ -69,6 +72,10 @@ public class ArrayPut { .functionHandler(ArrayPut::execute) .build(); + private ArrayPut() { + // disable construction + } + @SuppressWarnings("unused") @NonNull private static ISequence> execute(@NonNull IFunction function, @@ -78,7 +85,7 @@ private static ISequence> e 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).toArrayMember(); + @SuppressWarnings("unchecked") T member = (T) arguments.get(2).toCollectionValue(); return put(array, position, member).asSequence(); } 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 index 6cb62fcce..64a1a2019 100644 --- 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 @@ -47,11 +47,14 @@ import edu.umd.cs.findbugs.annotations.NonNull; -public class ArrayRemove { +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) @@ -67,6 +70,10 @@ public class ArrayRemove { .functionHandler(ArrayRemove::execute) .build(); + private ArrayRemove() { + // disable construction + } + @SuppressWarnings("unused") @NonNull private static ISequence> execute(@NonNull IFunction function, @@ -109,13 +116,13 @@ public static IArrayItem removeItems( public static IArrayItem remove( @NonNull IArrayItem array, @NonNull Collection positions) { - Set positionSet = positions instanceof Set ? (Set) positions : new HashSet(positions); + Set positionSet = positions instanceof Set ? (Set) positions : new HashSet<>(positions); - List removed = ObjectUtils.notNull(IntStream.range(1, array.size() + 1) + 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(removed); + 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 index b83e4a6a0..fba9e9ca7 100644 --- 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 @@ -43,11 +43,14 @@ import edu.umd.cs.findbugs.annotations.NonNull; -public class ArrayReverse { +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) @@ -58,6 +61,10 @@ public class ArrayReverse { .functionHandler(ArrayReverse::execute) .build(); + private ArrayReverse() { + // disable construction + } + @SuppressWarnings("unused") @NonNull private static ISequence> execute(@NonNull IFunction function, 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 index cad553484..26370a45c 100644 --- 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 @@ -46,6 +46,9 @@ public class ArraySize { 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) 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 index e8b3326e3..f0a4ab406 100644 --- 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 @@ -44,11 +44,14 @@ import edu.umd.cs.findbugs.annotations.NonNull; -public class ArraySubarray { +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) @@ -67,6 +70,9 @@ public class ArraySubarray { 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) @@ -87,6 +93,10 @@ public class ArraySubarray { .functionHandler(ArraySubarray::executeThreeArg) .build(); + private ArraySubarray() { + // disable construction + } + @SuppressWarnings("unused") @NonNull private static ISequence> executeTwoArg(@NonNull IFunction function, 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 index 6f5d1fe53..d45ed09df 100644 --- 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 @@ -41,11 +41,14 @@ import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; -public class ArrayTail { +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) @@ -56,6 +59,10 @@ public class ArrayTail { .functionHandler(ArrayTail::execute) .build(); + private ArrayTail() { + // disable construction + } + @SuppressWarnings("unused") @NonNull private static ISequence> execute(@NonNull IFunction function, 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 6af3c8230..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) 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 13ea87d4e..3e1d70f52 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 @@ -225,6 +225,27 @@ public DefaultFunctionLibrary() { // NOPMD - intentional // 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)); 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 b07098495..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 @@ -47,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() 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/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/NumericFunction.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/NumericFunction.java index ddbb03df6..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) 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/impl/AbstractStringMapKey.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractStringMapKey.java new file mode 100644 index 000000000..83bb7b822 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/AbstractStringMapKey.java @@ -0,0 +1,45 @@ +/* + * 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.item.function.IMapKey; + +public abstract class AbstractStringMapKey + implements IMapKey { + + @Override + public int hashCode() { + return getKey().asStringItem().hashCode(); + } + + @Override + public boolean equals(Object obj) { + return this == obj || + (obj instanceof AbstractStringMapKey + && getKey().asStringItem().equals(((AbstractStringMapKey) obj).getKey().asStringItem())); + } +} 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 index 4102d577d..b56173120 100644 --- 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 @@ -29,10 +29,16 @@ 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; @@ -42,21 +48,26 @@ * This implementation is inspired by the similar implementation provided by the * JDK. */ -public class ImmutableCollections { - protected static UnsupportedOperationException unsupported() { +public final class ImmutableCollections { + + private ImmutableCollections() { + // disable construction + } + + private static UnsupportedOperationException unsupported() { return new UnsupportedOperationException("method not supported"); } - public static abstract class AbstractImmutableCollection + public abstract static class AbstractImmutableCollection extends AbstractCollection { @Override - public final boolean add(T e) { + public final boolean add(T item) { throw unsupported(); } @Override - public final boolean addAll(Collection c) { + public final boolean addAll(Collection collection) { throw unsupported(); } @@ -66,12 +77,12 @@ public final void clear() { } @Override - public final boolean remove(Object o) { + public final boolean remove(Object obj) { throw unsupported(); } @Override - public final boolean removeAll(Collection c) { + public final boolean removeAll(Collection collection) { throw unsupported(); } @@ -81,17 +92,17 @@ public final boolean removeIf(Predicate filter) { } @Override - public final boolean retainAll(Collection c) { + public final boolean retainAll(Collection collection) { throw unsupported(); } } - public static abstract class AbstractImmutableList + public abstract static class AbstractImmutableList extends AbstractImmutableCollection implements List { @Override - public boolean addAll(int index, Collection c) { + public boolean addAll(int index, Collection collection) { throw unsupported(); } @@ -111,7 +122,7 @@ public T remove(int index) { } } - public static abstract class AbstractImmutableDelegatedCollection + public abstract static class AbstractImmutableDelegatedCollection extends AbstractImmutableList { @NonNull @@ -167,4 +178,84 @@ 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/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractDateItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractDateItem.java index 8f4649a2e..17e71cab0 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractDateItem.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractDateItem.java @@ -29,7 +29,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; public abstract class AbstractDateItem - extends AbstractAnyAtomicItem + extends AbstractTemporalItem implements IDateItem { /** * Construct a new item with the provided {@code value}. @@ -41,6 +41,11 @@ protected AbstractDateItem(@NonNull TYPE value) { super(value); } + @Override + public boolean hasTimezone() { + return true; + } + @Override public int hashCode() { return asZonedDateTime().hashCode(); diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractDateTimeItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractDateTimeItem.java index 9de39e709..9778e8dcc 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractDateTimeItem.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractDateTimeItem.java @@ -29,7 +29,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; public abstract class AbstractDateTimeItem - extends AbstractAnyAtomicItem + extends AbstractTemporalItem implements IDateTimeItem { /** * Construct a new item with the provided {@code value}. @@ -41,6 +41,11 @@ protected AbstractDateTimeItem(@NonNull TYPE value) { super(value); } + @Override + public boolean hasTimezone() { + return true; + } + @Override public int hashCode() { return asZonedDateTime().hashCode(); diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractDecimalItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractDecimalItem.java new file mode 100644 index 000000000..8ba4daf57 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractDecimalItem.java @@ -0,0 +1,66 @@ +/* + * 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.item.atomic; + +import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public abstract class AbstractDecimalItem + extends AbstractAnyAtomicItem + implements IDecimalItem { + + protected AbstractDecimalItem(@NonNull TYPE value) { + super(value); + } + + @Override + public IMapKey asMapKey() { + return new MapKey(); + } + + private final class MapKey + implements IMapKey { + + @Override + public IDecimalItem getKey() { + return AbstractDecimalItem.this; + } + + @Override + public int hashCode() { + return getKey().hashCode(); + } + + @Override + public boolean equals(Object obj) { + return this == obj || + (obj instanceof AbstractDecimalItem.MapKey + && getKey().asDecimal().equals(((AbstractDecimalItem.MapKey) obj).getKey().asDecimal())); + } + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractIntegerItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractIntegerItem.java index 56a181b26..427943c1c 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractIntegerItem.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractIntegerItem.java @@ -33,7 +33,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; public abstract class AbstractIntegerItem - extends AbstractAnyAtomicItem + extends AbstractDecimalItem implements IIntegerItem { /** * Construct a new item with the provided {@code value}. diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractStringItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractStringItem.java index 5c927cc32..3da0f8d2d 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractStringItem.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractStringItem.java @@ -26,6 +26,9 @@ package gov.nist.secauto.metaschema.core.metapath.item.atomic; +import gov.nist.secauto.metaschema.core.metapath.impl.AbstractStringMapKey; +import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey; + import edu.umd.cs.findbugs.annotations.NonNull; public abstract class AbstractStringItem @@ -47,6 +50,11 @@ public String asString() { return getValue(); } + @Override + public IMapKey asMapKey() { + return new MapKey(); + } + @Override public int hashCode() { return asString().hashCode(); @@ -58,4 +66,13 @@ public boolean equals(Object obj) { return this == obj || (obj instanceof IStringItem && compareTo((IStringItem) obj) == 0); } + + private final class MapKey + extends AbstractStringMapKey { + + @Override + public IStringItem getKey() { + return AbstractStringItem.this; + } + } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractTemporalItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractTemporalItem.java new file mode 100644 index 000000000..e36c1d75c --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractTemporalItem.java @@ -0,0 +1,74 @@ +/* + * 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.item.atomic; + +import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public abstract class AbstractTemporalItem + extends AbstractAnyAtomicItem + implements ITemporalItem { + + protected AbstractTemporalItem(@NonNull TYPE value) { + super(value); + } + + @Override + public IMapKey asMapKey() { + return new MapKey(); + } + + private final class MapKey + implements IMapKey { + + @Override + public ITemporalItem getKey() { + return AbstractTemporalItem.this; + } + + @Override + public int hashCode() { + return getKey().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (!(obj instanceof AbstractTemporalItem.MapKey)) { + return false; + } + + AbstractTemporalItem.MapKey other = (AbstractTemporalItem.MapKey) obj; + return hasTimezone() == other.getKey().hasTimezone() + && getKey().equals(other.getKey()); + } + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractUntypedAtomicItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractUntypedAtomicItem.java new file mode 100644 index 000000000..4435fd7a6 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractUntypedAtomicItem.java @@ -0,0 +1,55 @@ +/* + * 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.item.atomic; + +import gov.nist.secauto.metaschema.core.metapath.impl.AbstractStringMapKey; +import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public abstract class AbstractUntypedAtomicItem + extends AbstractAnyAtomicItem + implements IUntypedAtomicItem { + + protected AbstractUntypedAtomicItem(@NonNull TYPE value) { + super(value); + } + + @Override + public IMapKey asMapKey() { + return new MapKey(); + } + + private final class MapKey + extends AbstractStringMapKey { + + @Override + public IUntypedAtomicItem getKey() { + return AbstractUntypedAtomicItem.this; + } + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractUriItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractUriItem.java index f83932e31..98a979f81 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractUriItem.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/AbstractUriItem.java @@ -26,6 +26,9 @@ package gov.nist.secauto.metaschema.core.metapath.item.atomic; +import gov.nist.secauto.metaschema.core.metapath.impl.AbstractStringMapKey; +import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey; + import java.net.URI; import edu.umd.cs.findbugs.annotations.NonNull; @@ -50,6 +53,11 @@ public URI asUri() { return getValue(); } + @Override + public IMapKey asMapKey() { + return new MapKey(); + } + @Override public int hashCode() { return asUri().hashCode(); @@ -61,4 +69,13 @@ public boolean equals(Object obj) { return this == obj || (obj instanceof IAnyUriItem && compareTo((IAnyUriItem) obj) == 0); } + + private final class MapKey + extends AbstractStringMapKey { + + @Override + public IAnyUriItem getKey() { + return AbstractUriItem.this; + } + } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/Base64BinaryItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/Base64BinaryItemImpl.java index fd6928109..bac8f6af9 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/Base64BinaryItemImpl.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/Base64BinaryItemImpl.java @@ -28,6 +28,7 @@ import gov.nist.secauto.metaschema.core.datatype.adapter.Base64Adapter; import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider; +import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey; import java.nio.ByteBuffer; @@ -51,6 +52,11 @@ public ByteBuffer asByteBuffer() { return getValue(); } + @Override + public IMapKey asMapKey() { + return new MapKey(); + } + @Override public int hashCode() { return asByteBuffer().hashCode(); @@ -62,4 +68,23 @@ public boolean equals(Object obj) { return this == obj || (obj instanceof IBase64BinaryItem && compareTo((IBase64BinaryItem) obj) == 0); } + + private final class MapKey implements IMapKey { + @Override + public IBase64BinaryItem getKey() { + return Base64BinaryItemImpl.this; + } + + @Override + public int hashCode() { + return getKey().hashCode(); + } + + @Override + public boolean equals(Object obj) { + return this == obj || + (obj instanceof MapKey + && getKey().equals(((MapKey) obj).getKey())); + } + } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/BooleanItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/BooleanItemImpl.java index 9a8daf727..981f0d630 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/BooleanItemImpl.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/BooleanItemImpl.java @@ -28,6 +28,7 @@ import gov.nist.secauto.metaschema.core.datatype.IDataTypeAdapter; import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider; +import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey; import edu.umd.cs.findbugs.annotations.NonNull; @@ -77,6 +78,11 @@ public String toString() { return asString(); } + @Override + public IMapKey asMapKey() { + return new MapKey(); + } + @Override public int hashCode() { return Boolean.hashCode(booleanValue); @@ -88,4 +94,23 @@ public boolean equals(Object obj) { return this == obj || (obj instanceof IBooleanItem && compareTo((IBooleanItem) obj) == 0); } + + private final class MapKey implements IMapKey { + @Override + public IBooleanItem getKey() { + return BooleanItemImpl.this; + } + + @Override + public int hashCode() { + return getKey().hashCode(); + } + + @Override + public boolean equals(Object obj) { + return this == obj || + (obj instanceof MapKey + && getKey().equals(((MapKey) obj).getKey())); + } + } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/DayTimeDurationItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/DayTimeDurationItemImpl.java index 67768d16d..0069771f0 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/DayTimeDurationItemImpl.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/DayTimeDurationItemImpl.java @@ -28,6 +28,7 @@ import gov.nist.secauto.metaschema.core.datatype.adapter.DayTimeAdapter; import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider; +import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey; import java.time.Duration; @@ -51,6 +52,11 @@ public DayTimeAdapter getJavaTypeAdapter() { return MetaschemaDataTypeProvider.DAY_TIME_DURATION; } + @Override + public IMapKey asMapKey() { + return new MapKey(); + } + @Override public int hashCode() { return asDuration().hashCode(); @@ -62,4 +68,23 @@ public boolean equals(Object obj) { return this == obj || (obj instanceof IDayTimeDurationItem && compareTo((IDayTimeDurationItem) obj) == 0); } + + private final class MapKey implements IMapKey { + @Override + public IDayTimeDurationItem getKey() { + return DayTimeDurationItemImpl.this; + } + + @Override + public int hashCode() { + return getKey().hashCode(); + } + + @Override + public boolean equals(Object obj) { + return this == obj || + (obj instanceof MapKey + && getKey().equals(((MapKey) obj).getKey())); + } + } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/DecimalItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/DecimalItemImpl.java index 7e375c959..af4f04646 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/DecimalItemImpl.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/DecimalItemImpl.java @@ -36,8 +36,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; class DecimalItemImpl - extends AbstractAnyAtomicItem - implements IDecimalItem { + extends AbstractDecimalItem { public DecimalItemImpl(@NonNull BigDecimal value) { super(value); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IAnyAtomicItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IAnyAtomicItem.java index a915a9ce7..c905e4e90 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IAnyAtomicItem.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IAnyAtomicItem.java @@ -27,14 +27,15 @@ package gov.nist.secauto.metaschema.core.metapath.item.atomic; import gov.nist.secauto.metaschema.core.datatype.IDataTypeAdapter; -import gov.nist.secauto.metaschema.core.metapath.IStringValued; +import gov.nist.secauto.metaschema.core.metapath.IPrintable; +import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey; import gov.nist.secauto.metaschema.core.util.ObjectUtils; import java.util.Set; import edu.umd.cs.findbugs.annotations.NonNull; -public interface IAnyAtomicItem extends IAtomicValuedItem, IStringValued { +public interface IAnyAtomicItem extends IAtomicValuedItem, IPrintable { @NonNull Set> PRIMITIVE_ITEM_TYPES = ObjectUtils.notNull(Set.of( IStringItem.class, @@ -74,6 +75,9 @@ default IAnyAtomicItem toAtomicItem() { @NonNull String asString(); + @NonNull + IMapKey asMapKey(); + /** * Get a new {@link IStringItem} based on the the textual value of the item's * "wrapped" value. diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IAnyUriItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IAnyUriItem.java index 783af6d35..708d4b7b8 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IAnyUriItem.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IAnyUriItem.java @@ -120,7 +120,7 @@ default boolean isOpaque() { */ @NonNull default IAnyUriItem resolve(@NonNull IAnyUriItem other) { - return IAnyUriItem.valueOf(ObjectUtils.notNull(asUri().resolve(other.asUri()))); + return valueOf(ObjectUtils.notNull(asUri().resolve(other.asUri()))); } @Override diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IIPAddressItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IIPAddressItem.java index a84d82c78..e8907a9be 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IIPAddressItem.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IIPAddressItem.java @@ -38,9 +38,6 @@ public interface IIPAddressItem extends IUntypedAtomicItem { @NonNull IPAddress asIpAddress(); - @Override - int compareTo(IAnyAtomicItem item); - /** * Compares this value with the argument. * diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IPv4AddressItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IPv4AddressItemImpl.java index b86d4108a..f4660650e 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IPv4AddressItemImpl.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IPv4AddressItemImpl.java @@ -33,7 +33,7 @@ import inet.ipaddr.ipv4.IPv4Address; class IPv4AddressItemImpl - extends AbstractAnyAtomicItem + extends AbstractUntypedAtomicItem implements IIPv4AddressItem { public IPv4AddressItemImpl(@NonNull IPv4Address value) { diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IPv6AddressItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IPv6AddressItemImpl.java index 838bd8f37..69b0c398d 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IPv6AddressItemImpl.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/IPv6AddressItemImpl.java @@ -33,7 +33,7 @@ import inet.ipaddr.ipv6.IPv6Address; class IPv6AddressItemImpl - extends AbstractAnyAtomicItem + extends AbstractUntypedAtomicItem implements IIPv6AddressItem { public IPv6AddressItemImpl(@NonNull IPv6Address value) { diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/ITemporalItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/ITemporalItem.java new file mode 100644 index 000000000..a93b308b6 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/ITemporalItem.java @@ -0,0 +1,31 @@ +/* + * 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.item.atomic; + +public interface ITemporalItem extends IAnyAtomicItem { + boolean hasTimezone(); +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/MarkupLineItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/MarkupLineItemImpl.java index 1596e8d80..852dba9db 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/MarkupLineItemImpl.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/MarkupLineItemImpl.java @@ -33,7 +33,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; class MarkupLineItemImpl - extends AbstractAnyAtomicItem + extends AbstractUntypedAtomicItem implements IMarkupItem { public MarkupLineItemImpl(@NonNull MarkupLine value) { diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/MarkupMultiLineItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/MarkupMultiLineItemImpl.java index f782a2241..9229d1cb3 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/MarkupMultiLineItemImpl.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/MarkupMultiLineItemImpl.java @@ -33,7 +33,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; class MarkupMultiLineItemImpl - extends AbstractAnyAtomicItem + extends AbstractUntypedAtomicItem implements IMarkupItem { public MarkupMultiLineItemImpl(@NonNull MarkupMultiline value) { diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/UuidItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/UuidItemImpl.java index 261837ec7..99ef11b7b 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/UuidItemImpl.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/UuidItemImpl.java @@ -28,6 +28,7 @@ import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider; import gov.nist.secauto.metaschema.core.datatype.adapter.UuidAdapter; +import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey; import java.util.UUID; @@ -50,4 +51,28 @@ public UUID asUuid() { public UuidAdapter getJavaTypeAdapter() { return MetaschemaDataTypeProvider.UUID; } + + @Override + public IMapKey asMapKey() { + return new MapKey(); + } + + private final class MapKey implements IMapKey { + @Override + public IUuidItem getKey() { + return UuidItemImpl.this; + } + + @Override + public int hashCode() { + return getKey().hashCode(); + } + + @Override + public boolean equals(Object obj) { + return this == obj || + (obj instanceof MapKey + && getKey().asUuid().equals(((MapKey) obj).getKey().asUuid())); + } + } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/YearMonthDurationItemImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/YearMonthDurationItemImpl.java index 0719cad29..fa40dcfd5 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/YearMonthDurationItemImpl.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/atomic/YearMonthDurationItemImpl.java @@ -28,6 +28,7 @@ import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider; import gov.nist.secauto.metaschema.core.datatype.adapter.YearMonthAdapter; +import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey; import java.time.Period; import java.util.Objects; @@ -52,6 +53,11 @@ public YearMonthAdapter getJavaTypeAdapter() { return MetaschemaDataTypeProvider.YEAR_MONTH_DURATION; } + @Override + public IMapKey asMapKey() { + return new MapKey(); + } + @Override public int hashCode() { return Objects.hash(asPeriod()); @@ -63,4 +69,23 @@ public boolean equals(Object obj) { return this == obj || (obj instanceof IYearMonthDurationItem && compareTo((IYearMonthDurationItem) obj) == 0); } + + private final class MapKey implements IMapKey { + @Override + public IYearMonthDurationItem getKey() { + return YearMonthDurationItemImpl.this; + } + + @Override + public int hashCode() { + return getKey().hashCode(); + } + + @Override + public boolean equals(Object obj) { + return this == obj || + (obj instanceof MapKey + && getKey().equals(((MapKey) obj).getKey())); + } + } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/function/IArrayItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/function/IArrayItem.java index 754d186e0..064a71b29 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/function/IArrayItem.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/function/IArrayItem.java @@ -28,8 +28,8 @@ import gov.nist.secauto.metaschema.core.metapath.DynamicContext; import gov.nist.secauto.metaschema.core.metapath.ICollectionValue; +import gov.nist.secauto.metaschema.core.metapath.IPrintable; import gov.nist.secauto.metaschema.core.metapath.ISequence; -import gov.nist.secauto.metaschema.core.metapath.IStringValued; 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.ISequenceType; @@ -65,7 +65,7 @@ * the Metapath item type of array members */ @SuppressWarnings("PMD.ShortMethodName") -public interface IArrayItem extends IFunction, IItem, List, IStringValued { +public interface IArrayItem extends IFunction, IItem, List, IPrintable { @NonNull static IArrayItem empty() { return AbstractArrayItem.empty(); @@ -258,11 +258,10 @@ default Stream flatten() { .flatMap(ICollectionValue::flatten); } - @SuppressWarnings("unchecked") @NonNull static IArrayItem ofCollection( // NOPMD - intentional - @NonNull List items) { - return items.isEmpty() ? empty() : (IArrayItem) new ArrayItemN<>(items); + @NonNull List items) { + return items.isEmpty() ? empty() : new ArrayItemN<>(items); } /** @@ -289,7 +288,7 @@ static IArrayItem of() { * if the item is {@code null} */ @NonNull - static IArrayItem of(T e1) { + static IArrayItem of(@NonNull T e1) { return new ArrayItemN<>(e1); } @@ -307,7 +306,7 @@ static IArrayItem of(T e1) { * if an item is {@code null} */ @NonNull - static IArrayItem of(T e1, T e2) { + static IArrayItem of(@NonNull T e1, @NonNull T e2) { return new ArrayItemN<>(e1, e2); } @@ -327,7 +326,7 @@ static IArrayItem of(T e1, T e2) { * if an item is {@code null} */ @NonNull - static IArrayItem of(T e1, T e2, T e3) { + static IArrayItem of(@NonNull T e1, @NonNull T e2, @NonNull T e3) { return new ArrayItemN<>(e1, e2, e3); } @@ -349,7 +348,7 @@ static IArrayItem of(T e1, T e2, T e3) { * if an item is {@code null} */ @NonNull - static IArrayItem of(T e1, T e2, T e3, T e4) { + static IArrayItem of(@NonNull T e1, @NonNull T e2, @NonNull T e3, @NonNull T e4) { return new ArrayItemN<>(e1, e2, e3, e4); } @@ -373,7 +372,8 @@ static IArrayItem of(T e1, T e2, T e3, T e4) { * if an item is {@code null} */ @NonNull - static IArrayItem of(T e1, T e2, T e3, T e4, T e5) { + static IArrayItem of(@NonNull T e1, @NonNull T e2, @NonNull T e3, @NonNull T e4, + @NonNull T e5) { return new ArrayItemN<>(e1, e2, e3, e4, e5); } @@ -399,7 +399,8 @@ static IArrayItem of(T e1, T e2, T e3, T e4, T e * if an item is {@code null} */ @NonNull - static IArrayItem of(T e1, T e2, T e3, T e4, T e5, T e6) { + static IArrayItem of(@NonNull T e1, @NonNull T e2, @NonNull T e3, @NonNull T e4, + @NonNull T e5, @NonNull T e6) { return new ArrayItemN<>(e1, e2, e3, e4, e5, e6); } @@ -427,7 +428,8 @@ static IArrayItem of(T e1, T e2, T e3, T e4, T e * if an item is {@code null} */ @NonNull - static IArrayItem of(T e1, T e2, T e3, T e4, T e5, T e6, T e7) { + static IArrayItem of(@NonNull T e1, @NonNull T e2, @NonNull T e3, @NonNull T e4, + @NonNull T e5, @NonNull T e6, @NonNull T e7) { return new ArrayItemN<>(e1, e2, e3, e4, e5, e6, e7); } @@ -457,7 +459,8 @@ static IArrayItem of(T e1, T e2, T e3, T e4, T e * if an item is {@code null} */ @NonNull - static IArrayItem of(T e1, T e2, T e3, T e4, T e5, T e6, T e7, T e8) { + static IArrayItem of(@NonNull T e1, @NonNull T e2, @NonNull T e3, @NonNull T e4, + @NonNull T e5, @NonNull T e6, @NonNull T e7, @NonNull T e8) { return new ArrayItemN<>(e1, e2, e3, e4, e5, e6, e7, e8); } @@ -489,7 +492,8 @@ static IArrayItem of(T e1, T e2, T e3, T e4, T e * if an item is {@code null} */ @NonNull - static IArrayItem of(T e1, T e2, T e3, T e4, T e5, T e6, T e7, T e8, T e9) { + static IArrayItem of(@NonNull T e1, @NonNull T e2, @NonNull T e3, @NonNull T e4, + @NonNull T e5, @NonNull T e6, @NonNull T e7, @NonNull T e8, @NonNull T e9) { return new ArrayItemN<>(e1, e2, e3, e4, e5, e6, e7, e8, e9); } @@ -523,7 +527,8 @@ static IArrayItem of(T e1, T e2, T e3, T e4, T e * if an item is {@code null} */ @NonNull - static IArrayItem of(T e1, T e2, T e3, T e4, T e5, T e6, T e7, T e8, T e9, T e10) { + static IArrayItem of(@NonNull T e1, @NonNull T e2, @NonNull T e3, @NonNull T e4, + @NonNull T e5, @NonNull T e6, @NonNull T e7, @NonNull T e8, @NonNull T e9, @NonNull T e10) { return new ArrayItemN<>(e1, e2, e3, e4, e5, e6, e7, e8, e9, e10); } @@ -559,11 +564,10 @@ static IArrayItem of(@NonNull T... items) { * {@code Collection} * @throws NullPointerException * if collection is null, or if it contains any nulls - * @since 10 */ @SuppressWarnings("unchecked") @NonNull - static IArrayItem copyOf(Collection collection) { + static IArrayItem copyOf(@NonNull Collection collection) { return collection instanceof IArrayItem ? (IArrayItem) collection : collection.isEmpty() diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/function/IMapItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/function/IMapItem.java new file mode 100644 index 000000000..b1b2a69ba --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/function/IMapItem.java @@ -0,0 +1,756 @@ +/* + * 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.item.function; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ICollectionValue; +import gov.nist.secauto.metaschema.core.metapath.IPrintable; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +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.ISequenceType; +import gov.nist.secauto.metaschema.core.metapath.impl.AbstractArrayItem; +import gov.nist.secauto.metaschema.core.metapath.impl.AbstractMapItem; +import gov.nist.secauto.metaschema.core.metapath.impl.MapItemN; +import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.xml.namespace.QName; + +import edu.umd.cs.findbugs.annotations.NonNull; + +/** + * Represents a mapping of {@link IMapKey} keys to values. + * + * @param + * the value type + */ +public interface IMapItem + extends IFunction, IItem, Map, IPrintable { + @NonNull + static IMapItem empty() { + return AbstractMapItem.empty(); + } + + @Override + default QName getQName() { + return AbstractArrayItem.QNAME; + } + + @Override + default Set getProperties() { + return AbstractArrayItem.PROPERTIES; + } + + @Override + default boolean isDeterministic() { + return true; + } + + @Override + default boolean isContextDepenent() { + return false; + } + + @Override + default boolean isFocusDepenent() { + return false; + } + + @Override + default List getArguments() { + return AbstractArrayItem.ARGUMENTS; + } + + @Override + default int arity() { + return 1; + } + + @Override + default boolean isArityUnbounded() { + return false; + } + + @Override + default ISequenceType getResult() { + return AbstractArrayItem.RESULT; + } + + @Override + ISequence execute(List> arguments, DynamicContext dynamicContext, ISequence focus); + + @Override + default String toSignature() { + return "array()"; + } + + @Override + Map getValue(); + + @Override + default boolean hasValue() { + return true; + } + + /** + * Determine if this sequence is empty. + * + * @return {@code true} if the sequence contains no items, or {@code false} + * otherwise + */ + @Override + default boolean isEmpty() { + return getValue().isEmpty(); + } + + /** + * Get the count of items in this sequence. + * + * @return the count of items + */ + @Override + default int size() { + return getValue().size(); + + } + + @Override + default ISequence> asSequence() { + return ISequence.of(this); + } + + @NonNull + static IMapItem ofCollection( // NOPMD - intentional + @NonNull Map map) { + return map.isEmpty() ? empty() : new MapItemN<>(map); + } + + /** + * Returns an unmodifiable map item containing zero mappings. + * + * @param + * the value type + * @return an empty {@code IMapItem} + */ + @NonNull + static IMapItem of() { + return AbstractMapItem.empty(); + } + + /** + * Returns an unmodifiable map item containing a single mapping. + * + * @param + * the {@code Map}'s key type + * @param + * the {@code Map}'s value type + * @param k1 + * the mapping's key + * @param v1 + * the mapping's value + * @return a {@code Map} containing the specified mapping + * @throws NullPointerException + * if the key or the value is {@code null} + */ + @NonNull + static IMapItem of(@NonNull K k1, @NonNull V v1) { + return new MapItemN<>(entry(k1, v1)); + } + + /** + * Returns an unmodifiable map item containing two mappings. + * + * @param + * the {@code Map}'s key type + * @param + * the {@code Map}'s value type + * @param k1 + * the first mapping's key + * @param v1 + * the first mapping's value + * @param k2 + * the second mapping's key + * @param v2 + * the second mapping's value + * @return a {@code Map} containing the specified mappings + * @throws IllegalArgumentException + * if the keys are duplicates + * @throws NullPointerException + * if any key or value is {@code null} + */ + @NonNull + static IMapItem of( + @NonNull K k1, @NonNull V v1, + @NonNull K k2, @NonNull V v2) { + return new MapItemN<>( + entry(k1, v1), + entry(k2, v2)); + } + + /** + * Returns an unmodifiable map item containing three mappings. + * + * @param + * the {@code Map}'s key type + * @param + * the {@code Map}'s value type + * @param k1 + * the first mapping's key + * @param v1 + * the first mapping's value + * @param k2 + * the second mapping's key + * @param v2 + * the second mapping's value + * @param k3 + * the third mapping's key + * @param v3 + * the third mapping's value + * @return a {@code Map} containing the specified mappings + * @throws IllegalArgumentException + * if there are any duplicate keys + * @throws NullPointerException + * if any key or value is {@code null} + */ + @NonNull + static + IMapItem of( + @NonNull K k1, @NonNull V v1, + @NonNull K k2, @NonNull V v2, + @NonNull K k3, @NonNull V v3) { + return new MapItemN<>( + entry(k1, v1), + entry(k2, v2), + entry(k3, v3)); + } + + /** + * Returns an unmodifiable map item containing four mappings. + * + * @param + * the {@code Map}'s key type + * @param + * the {@code Map}'s value type + * @param k1 + * the first mapping's key + * @param v1 + * the first mapping's value + * @param k2 + * the second mapping's key + * @param v2 + * the second mapping's value + * @param k3 + * the third mapping's key + * @param v3 + * the third mapping's value + * @param k4 + * the fourth mapping's key + * @param v4 + * the fourth mapping's value + * @return a {@code Map} containing the specified mappings + * @throws IllegalArgumentException + * if there are any duplicate keys + * @throws NullPointerException + * if any key or value is {@code null} + */ + @NonNull + static + IMapItem of( + @NonNull K k1, @NonNull V v1, + @NonNull K k2, @NonNull V v2, + @NonNull K k3, @NonNull V v3, + @NonNull K k4, @NonNull V v4) { + return new MapItemN<>( + entry(k1, v1), + entry(k2, v2), + entry(k3, v3), + entry(k4, v4)); + } + + /** + * Returns an unmodifiable map item containing five mappings. + * + * @param + * the {@code Map}'s key type + * @param + * the {@code Map}'s value type + * @param k1 + * the first mapping's key + * @param v1 + * the first mapping's value + * @param k2 + * the second mapping's key + * @param v2 + * the second mapping's value + * @param k3 + * the third mapping's key + * @param v3 + * the third mapping's value + * @param k4 + * the fourth mapping's key + * @param v4 + * the fourth mapping's value + * @param k5 + * the fifth mapping's key + * @param v5 + * the fifth mapping's value + * @return a {@code Map} containing the specified mappings + * @throws IllegalArgumentException + * if there are any duplicate keys + * @throws NullPointerException + * if any key or value is {@code null} + */ + @NonNull + static + IMapItem of( + @NonNull K k1, @NonNull V v1, + @NonNull K k2, @NonNull V v2, + @NonNull K k3, @NonNull V v3, + @NonNull K k4, @NonNull V v4, + @NonNull K k5, @NonNull V v5) { + return new MapItemN<>( + entry(k1, v1), + entry(k2, v2), + entry(k3, v3), + entry(k4, v4), + entry(k5, v5)); + } + + /** + * Returns an unmodifiable map item containing six mappings. + * + * @param + * the {@code Map}'s key type + * @param + * the {@code Map}'s value type + * @param k1 + * the first mapping's key + * @param v1 + * the first mapping's value + * @param k2 + * the second mapping's key + * @param v2 + * the second mapping's value + * @param k3 + * the third mapping's key + * @param v3 + * the third mapping's value + * @param k4 + * the fourth mapping's key + * @param v4 + * the fourth mapping's value + * @param k5 + * the fifth mapping's key + * @param v5 + * the fifth mapping's value + * @param k6 + * the sixth mapping's key + * @param v6 + * the sixth mapping's value + * @return a {@code Map} containing the specified mappings + * @throws IllegalArgumentException + * if there are any duplicate keys + * @throws NullPointerException + * if any key or value is {@code null} + */ + @SuppressWarnings("PMD.ExcessiveParameterList") + @NonNull + static + IMapItem of( + @NonNull K k1, @NonNull V v1, + @NonNull K k2, @NonNull V v2, + @NonNull K k3, @NonNull V v3, + @NonNull K k4, @NonNull V v4, + @NonNull K k5, @NonNull V v5, + @NonNull K k6, @NonNull V v6) { + return new MapItemN<>( + entry(k1, v1), + entry(k2, v2), + entry(k3, v3), + entry(k4, v4), + entry(k5, v5), + entry(k6, v6)); + } + + /** + * Returns an unmodifiable map item containing seven mappings. + * + * @param + * the {@code Map}'s key type + * @param + * the {@code Map}'s value type + * @param k1 + * the first mapping's key + * @param v1 + * the first mapping's value + * @param k2 + * the second mapping's key + * @param v2 + * the second mapping's value + * @param k3 + * the third mapping's key + * @param v3 + * the third mapping's value + * @param k4 + * the fourth mapping's key + * @param v4 + * the fourth mapping's value + * @param k5 + * the fifth mapping's key + * @param v5 + * the fifth mapping's value + * @param k6 + * the sixth mapping's key + * @param v6 + * the sixth mapping's value + * @param k7 + * the seventh mapping's key + * @param v7 + * the seventh mapping's value + * @return a {@code Map} containing the specified mappings + * @throws IllegalArgumentException + * if there are any duplicate keys + * @throws NullPointerException + * if any key or value is {@code null} + */ + @SuppressWarnings("PMD.ExcessiveParameterList") + @NonNull + static IMapItem of( + @NonNull K k1, @NonNull V v1, + @NonNull K k2, @NonNull V v2, + @NonNull K k3, @NonNull V v3, + @NonNull K k4, @NonNull V v4, + @NonNull K k5, @NonNull V v5, + @NonNull K k6, @NonNull V v6, + @NonNull K k7, @NonNull V v7) { + return new MapItemN<>( + entry(k1, v1), + entry(k2, v2), + entry(k3, v3), + entry(k4, v4), + entry(k5, v5), + entry(k6, v6), + entry(k7, v7)); + } + + /** + * Returns an unmodifiable map item containing eight mappings. See + * Unmodifiable Maps for details. + * + * @param + * the {@code Map}'s key type + * @param + * the {@code Map}'s value type + * @param k1 + * the first mapping's key + * @param v1 + * the first mapping's value + * @param k2 + * the second mapping's key + * @param v2 + * the second mapping's value + * @param k3 + * the third mapping's key + * @param v3 + * the third mapping's value + * @param k4 + * the fourth mapping's key + * @param v4 + * the fourth mapping's value + * @param k5 + * the fifth mapping's key + * @param v5 + * the fifth mapping's value + * @param k6 + * the sixth mapping's key + * @param v6 + * the sixth mapping's value + * @param k7 + * the seventh mapping's key + * @param v7 + * the seventh mapping's value + * @param k8 + * the eighth mapping's key + * @param v8 + * the eighth mapping's value + * @return a {@code Map} containing the specified mappings + * @throws IllegalArgumentException + * if there are any duplicate keys + * @throws NullPointerException + * if any key or value is {@code null} + */ + @SuppressWarnings("PMD.ExcessiveParameterList") + @NonNull + static + IMapItem of( + @NonNull K k1, @NonNull V v1, + @NonNull K k2, @NonNull V v2, + @NonNull K k3, @NonNull V v3, + @NonNull K k4, @NonNull V v4, + @NonNull K k5, @NonNull V v5, + @NonNull K k6, @NonNull V v6, + @NonNull K k7, @NonNull V v7, + @NonNull K k8, @NonNull V v8) { + return new MapItemN<>( + entry(k1, v1), + entry(k2, v2), + entry(k3, v3), + entry(k4, v4), + entry(k5, v5), + entry(k6, v6), + entry(k7, v7), + entry(k8, v8)); + } + + /** + * Returns an unmodifiable map item containing nine mappings. + * + * @param + * the {@code Map}'s key type + * @param + * the {@code Map}'s value type + * @param k1 + * the first mapping's key + * @param v1 + * the first mapping's value + * @param k2 + * the second mapping's key + * @param v2 + * the second mapping's value + * @param k3 + * the third mapping's key + * @param v3 + * the third mapping's value + * @param k4 + * the fourth mapping's key + * @param v4 + * the fourth mapping's value + * @param k5 + * the fifth mapping's key + * @param v5 + * the fifth mapping's value + * @param k6 + * the sixth mapping's key + * @param v6 + * the sixth mapping's value + * @param k7 + * the seventh mapping's key + * @param v7 + * the seventh mapping's value + * @param k8 + * the eighth mapping's key + * @param v8 + * the eighth mapping's value + * @param k9 + * the ninth mapping's key + * @param v9 + * the ninth mapping's value + * @return a {@code Map} containing the specified mappings + * @throws IllegalArgumentException + * if there are any duplicate keys + * @throws NullPointerException + * if any key or value is {@code null} + */ + @SuppressWarnings("PMD.ExcessiveParameterList") + @NonNull + static + IMapItem of( + @NonNull K k1, @NonNull V v1, + @NonNull K k2, @NonNull V v2, + @NonNull K k3, @NonNull V v3, + @NonNull K k4, @NonNull V v4, + @NonNull K k5, @NonNull V v5, + @NonNull K k6, @NonNull V v6, + @NonNull K k7, @NonNull V v7, + @NonNull K k8, @NonNull V v8, + @NonNull K k9, @NonNull V v9) { + return new MapItemN<>(entry(k1, v1), entry(k2, v2), entry(k3, v3), entry(k4, v4), entry(k5, v5), entry(k6, v6), + entry(k7, v7), entry(k8, v8), entry(k9, v9)); + } + + /** + * Returns an unmodifiable map item containing ten mappings. + * + * @param + * the {@code Map}'s key type + * @param + * the {@code Map}'s value type + * @param k1 + * the first mapping's key + * @param v1 + * the first mapping's value + * @param k2 + * the second mapping's key + * @param v2 + * the second mapping's value + * @param k3 + * the third mapping's key + * @param v3 + * the third mapping's value + * @param k4 + * the fourth mapping's key + * @param v4 + * the fourth mapping's value + * @param k5 + * the fifth mapping's key + * @param v5 + * the fifth mapping's value + * @param k6 + * the sixth mapping's key + * @param v6 + * the sixth mapping's value + * @param k7 + * the seventh mapping's key + * @param v7 + * the seventh mapping's value + * @param k8 + * the eighth mapping's key + * @param v8 + * the eighth mapping's value + * @param k9 + * the ninth mapping's key + * @param v9 + * the ninth mapping's value + * @param k10 + * the tenth mapping's key + * @param v10 + * the tenth mapping's value + * @return a {@code Map} containing the specified mappings + * @throws IllegalArgumentException + * if there are any duplicate keys + * @throws NullPointerException + * if any key or value is {@code null} + */ + @SuppressWarnings("PMD.ExcessiveParameterList") + @NonNull + static IMapItem of( + @NonNull K k1, @NonNull V v1, + @NonNull K k2, @NonNull V v2, + @NonNull K k3, @NonNull V v3, + @NonNull K k4, @NonNull V v4, + @NonNull K k5, @NonNull V v5, + @NonNull K k6, @NonNull V v6, + @NonNull K k7, @NonNull V v7, + @NonNull K k8, @NonNull V v8, + @NonNull K k9, @NonNull V v9, + @NonNull K k10, @NonNull V v10) { + return new MapItemN<>( + entry(k1, v1), + entry(k2, v2), + entry(k3, v3), + entry(k4, v4), + entry(k5, v5), + entry(k6, v6), + entry(k7, v7), + entry(k8, v8), + entry(k9, v9), + entry(k10, v10)); + } + + /** + * Returns an unmodifiable map item containing keys and values extracted from + * the given entries. The entries themselves are not stored in the map. + * + * @param + * the {@code Map}'s key type + * @param + * the {@code Map}'s value type + * @param entries + * {@code Map.Entry}s containing the keys and values from which the map + * is populated + * @return a {@code Map} containing the specified mappings + * @throws IllegalArgumentException + * if there are any duplicate keys + * @throws NullPointerException + * if any entry, key, or value is {@code null}, or if the + * {@code entries} array is {@code null} + */ + @SafeVarargs + @SuppressWarnings("varargs") + @NonNull + static + IMapItem ofEntries(Map.Entry... entries) { + return entries.length == 0 ? empty() : new MapItemN<>(entries); + } + + /** + * Returns an unmodifiable {@link Entry} containing the given key and value. + * + * @param + * the value's type + * @param key + * the key + * @param value + * the value + * @return an {@code Entry} containing the specified key and value + * @throws NullPointerException + * if the key or value is {@code null} + */ + @NonNull + static Map.Entry entry(@NonNull IAnyAtomicItem key, @NonNull V value) { + return entry(key.asMapKey(), value); + } + + @SuppressWarnings("null") + @NonNull + static Map.Entry entry(@NonNull IMapKey key, @NonNull V value) { + return Map.entry(key, value); + } + + /** + * Returns an unmodifiable Map item containing the entries of the given Map. The + * given Map must not be null, and it must not contain any null keys or values. + * If the given Map is subsequently modified, the returned Map will not reflect + * such modifications. + * + * @param + * the {@code Map}'s key type + * @param + * the {@code Map}'s value type + * @param map + * a {@code Map} from which entries are drawn, must be non-null + * @return a {@code Map} containing the entries of the given {@code Map} + * @throws NullPointerException + * if map is null, or if it contains any null keys or values + */ + @SuppressWarnings("unchecked") + @NonNull + static + IMapItem copyOf(Map map) { + return map instanceof IMapItem + ? (IMapItem) map + : map.isEmpty() + ? empty() + : new MapItemN<>(new LinkedHashMap<>(map)); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/function/IMapKey.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/function/IMapKey.java new file mode 100644 index 000000000..33ad72909 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/function/IMapKey.java @@ -0,0 +1,43 @@ +/* + * 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.item.function; + +import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public interface IMapKey { + + @NonNull + IAnyAtomicItem getKey(); + + @Override + int hashCode(); + + @Override + boolean equals(Object obj); +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/AbstractGlobalAssemblyDefinition.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/AbstractGlobalAssemblyDefinition.java index b36c09198..7188a7ff0 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/AbstractGlobalAssemblyDefinition.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/AbstractGlobalAssemblyDefinition.java @@ -48,6 +48,6 @@ public abstract class AbstractGlobalAssemblyDefinition< CHOICE_GROUP> { protected AbstractGlobalAssemblyDefinition(@NonNull MODULE module) { - super(module, name -> module.toModelQName(name)); + super(module, module::toModelQName); } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/AbstractGlobalFieldDefinition.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/AbstractGlobalFieldDefinition.java index f5466ad4d..425567667 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/AbstractGlobalFieldDefinition.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/AbstractGlobalFieldDefinition.java @@ -36,6 +36,6 @@ public abstract class AbstractGlobalFieldDefinition< implements IFieldDefinition, IFeatureContainerFlag { protected AbstractGlobalFieldDefinition(@NonNull MODULE module) { - super(module, name -> module.toModelQName(name)); + super(module, module::toModelQName); } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/AbstractGlobalFlagDefinition.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/AbstractGlobalFlagDefinition.java index 4748c2327..ab8056991 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/AbstractGlobalFlagDefinition.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/AbstractGlobalFlagDefinition.java @@ -33,6 +33,6 @@ public abstract class AbstractGlobalFlagDefinition module.toFlagQName(name)); + super(module, module::toFlagQName); } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/FlagContainerBuilder.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/FlagContainerBuilder.java index b702706e8..105ac46e1 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/FlagContainerBuilder.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/FlagContainerBuilder.java @@ -66,7 +66,7 @@ public IFlagContainerBuilder flag(@NonNull T instance) { @Override public IContainerFlagSupport build() { - IContainerFlagSupport retval = null; + IContainerFlagSupport retval; if (flags.isEmpty()) { retval = IContainerFlagSupport.empty(); } else { diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/XmlFieldInstance.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/XmlFieldInstance.java index 2db9e884c..03d503eef 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/XmlFieldInstance.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/XmlFieldInstance.java @@ -91,7 +91,7 @@ protected final FieldReferenceType getXmlObject() { @Override public boolean isInXmlWrapped() { - return getXmlObject().getInXml().booleanValue(); + return getXmlObject().getInXml(); } @Override diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/XmlFlagInstance.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/XmlFlagInstance.java index 895c3fe29..409ee4dc1 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/XmlFlagInstance.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/XmlFlagInstance.java @@ -136,7 +136,7 @@ public MarkupMultiline getRemarks() { @Override public boolean isRequired() { return getXmlObject().isSetRequired() ? getXmlObject().getRequired() - : IFlagInstance.DEFAULT_FLAG_REQUIRED; + : DEFAULT_FLAG_REQUIRED; } // ------------------------------------- diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/XmlGlobalAssemblyDefinition.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/XmlGlobalAssemblyDefinition.java index 8959d04f3..aff654c94 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/XmlGlobalAssemblyDefinition.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/XmlGlobalAssemblyDefinition.java @@ -36,7 +36,6 @@ import gov.nist.secauto.metaschema.core.model.IChoiceInstance; import gov.nist.secauto.metaschema.core.model.IContainerFlagSupport; import gov.nist.secauto.metaschema.core.model.IContainerModelAssemblySupport; -import gov.nist.secauto.metaschema.core.model.IDefinition; import gov.nist.secauto.metaschema.core.model.IFieldInstanceAbsolute; import gov.nist.secauto.metaschema.core.model.IFlagInstance; import gov.nist.secauto.metaschema.core.model.IModelInstanceAbsolute; @@ -215,7 +214,7 @@ public Integer getRootIndex() { @SuppressWarnings("null") @Override public ModuleScopeEnum getModuleScope() { - return getXmlObject().isSetScope() ? getXmlObject().getScope() : IDefinition.DEFAULT_DEFINITION_MODEL_SCOPE; + return getXmlObject().isSetScope() ? getXmlObject().getScope() : DEFAULT_DEFINITION_MODEL_SCOPE; } @SuppressWarnings("null") diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/XmlGlobalFieldDefinition.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/XmlGlobalFieldDefinition.java index 299b0d86d..6494c4b34 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/XmlGlobalFieldDefinition.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/XmlGlobalFieldDefinition.java @@ -33,7 +33,6 @@ import gov.nist.secauto.metaschema.core.model.AbstractGlobalFieldDefinition; import gov.nist.secauto.metaschema.core.model.IAttributable; import gov.nist.secauto.metaschema.core.model.IContainerFlagSupport; -import gov.nist.secauto.metaschema.core.model.IDefinition; import gov.nist.secauto.metaschema.core.model.IFieldInstance; import gov.nist.secauto.metaschema.core.model.IFlagInstance; import gov.nist.secauto.metaschema.core.model.ModuleScopeEnum; @@ -212,7 +211,7 @@ public String getJsonValueKeyName() { @SuppressWarnings("null") @Override public ModuleScopeEnum getModuleScope() { - return getXmlObject().isSetScope() ? getXmlObject().getScope() : IDefinition.DEFAULT_DEFINITION_MODEL_SCOPE; + return getXmlObject().isSetScope() ? getXmlObject().getScope() : DEFAULT_DEFINITION_MODEL_SCOPE; } @SuppressWarnings("null") diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/XmlGlobalFlagDefinition.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/XmlGlobalFlagDefinition.java index a9e14eda2..07f43676a 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/XmlGlobalFlagDefinition.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/XmlGlobalFlagDefinition.java @@ -32,7 +32,6 @@ import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline; import gov.nist.secauto.metaschema.core.model.AbstractGlobalFlagDefinition; import gov.nist.secauto.metaschema.core.model.IAttributable; -import gov.nist.secauto.metaschema.core.model.IDefinition; import gov.nist.secauto.metaschema.core.model.IFlagInstance; import gov.nist.secauto.metaschema.core.model.ModuleScopeEnum; import gov.nist.secauto.metaschema.core.model.constraint.ISource; @@ -120,7 +119,7 @@ protected final GlobalFlagDefinitionType getXmlFlag() { @SuppressWarnings("null") @Override public ModuleScopeEnum getModuleScope() { - return getXmlFlag().isSetScope() ? getXmlFlag().getScope() : IDefinition.DEFAULT_DEFINITION_MODEL_SCOPE; + return getXmlFlag().isSetScope() ? getXmlFlag().getScope() : DEFAULT_DEFINITION_MODEL_SCOPE; } @SuppressWarnings("null") diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/XmlInlineFlagDefinition.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/XmlInlineFlagDefinition.java index 12a99b3de..f4d0ee94f 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/XmlInlineFlagDefinition.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/XmlInlineFlagDefinition.java @@ -150,8 +150,7 @@ public Integer getIndex() { @Override public boolean isRequired() { - return getXmlObject().isSetRequired() ? getXmlObject().getRequired() - : IFlagInstance.DEFAULT_FLAG_REQUIRED; + return getXmlObject().isSetRequired() ? getXmlObject().getRequired() : DEFAULT_FLAG_REQUIRED; } @SuppressWarnings("null") diff --git a/core/src/main/java/module-info.java b/core/src/main/java/module-info.java index 69c153471..d79ae1575 100644 --- a/core/src/main/java/module-info.java +++ b/core/src/main/java/module-info.java @@ -1,4 +1,3 @@ - /* * 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 @@ -25,6 +24,33 @@ * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. */ +/* + * 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. + */ + import gov.nist.secauto.metaschema.core.datatype.IDataTypeProvider; import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider; import gov.nist.secauto.metaschema.core.datatype.markup.MarkupDataTypeProvider; @@ -87,6 +113,7 @@ exports gov.nist.secauto.metaschema.core.metapath.function.library; exports gov.nist.secauto.metaschema.core.metapath.item; exports gov.nist.secauto.metaschema.core.metapath.item.atomic; + exports gov.nist.secauto.metaschema.core.metapath.item.function; exports gov.nist.secauto.metaschema.core.metapath.item.node; exports gov.nist.secauto.metaschema.core.model; exports gov.nist.secauto.metaschema.core.model.constraint; diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/TestUtils.java b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/TestUtils.java index df748cd0d..f987a9791 100644 --- a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/TestUtils.java +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/TestUtils.java @@ -28,6 +28,7 @@ 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.IAnyUriItem; import gov.nist.secauto.metaschema.core.metapath.item.atomic.IBooleanItem; import gov.nist.secauto.metaschema.core.metapath.item.atomic.IDayTimeDurationItem; @@ -36,6 +37,8 @@ import gov.nist.secauto.metaschema.core.metapath.item.atomic.IStringItem; import gov.nist.secauto.metaschema.core.metapath.item.atomic.IYearMonthDurationItem; 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.metapath.item.function.IMapKey; import gov.nist.secauto.metaschema.core.util.CollectionUtil; import gov.nist.secauto.metaschema.core.util.ObjectUtils; @@ -44,6 +47,7 @@ import java.math.MathContext; import java.net.URI; import java.util.List; +import java.util.Map; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; @@ -75,6 +79,19 @@ public static IArrayItem array(@NonNull T... ite return IArrayItem.of(items); } + @SafeVarargs + @NonNull + public static IMapItem map(@NonNull Map.Entry... entries) { + return IMapItem.ofEntries(entries); + } + + @NonNull + public static Map.Entry entry( + @NonNull IAnyAtomicItem key, + @NonNull T value) { + return IMapItem.entry(key, value); + } + @NonNull public static IBooleanItem bool(boolean value) { return IBooleanItem.valueOf(value); diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapContainsTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapContainsTest.java new file mode 100644 index 000000000..e32735fdc --- /dev/null +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapContainsTest.java @@ -0,0 +1,74 @@ +/* + * 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 static gov.nist.secauto.metaschema.core.metapath.TestUtils.bool; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import gov.nist.secauto.metaschema.core.metapath.ExpressionTestBase; +import gov.nist.secauto.metaschema.core.metapath.MetapathExpression; +import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.LookupTest; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import edu.umd.cs.findbugs.annotations.NonNull; + +class MapContainsTest + extends ExpressionTestBase { + private static Stream provideValues() { // NOPMD - false positive + return Stream.of( + Arguments.of( + bool(true), + "let $week := " + LookupTest.WEEKDAYS_GERMAN + " return map:contains($week, 2)"), + Arguments.of( + bool(false), + "let $week := " + LookupTest.WEEKDAYS_GERMAN + " return map:contains($week, 9)"), + Arguments.of( + bool(false), + "map:contains(map{}, \"xyz\")"), + Arguments.of( + bool(true), + "map:contains(map{\"xyz\":23}, \"xyz\")"), + Arguments.of( + bool(true), + "map:contains(map{\"abc\":23, \"xyz\":()}, \"xyz\")")); + } + + @ParameterizedTest + @MethodSource("provideValues") + void testExpression(@NonNull IItem expected, @NonNull String metapath) { + + IItem result = MetapathExpression.compile(metapath) + .evaluateAs(null, MetapathExpression.ResultType.NODE, newDynamicContext()); + assertEquals(expected, result); + } +} diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapEntryTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapEntryTest.java new file mode 100644 index 000000000..46c2dff1d --- /dev/null +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapEntryTest.java @@ -0,0 +1,65 @@ +/* + * 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 static gov.nist.secauto.metaschema.core.metapath.TestUtils.entry; +import static gov.nist.secauto.metaschema.core.metapath.TestUtils.map; +import static gov.nist.secauto.metaschema.core.metapath.TestUtils.string; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import gov.nist.secauto.metaschema.core.metapath.ExpressionTestBase; +import gov.nist.secauto.metaschema.core.metapath.MetapathExpression; +import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.IMapItem; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import edu.umd.cs.findbugs.annotations.NonNull; + +class MapEntryTest + extends ExpressionTestBase { + + private static Stream provideValues() { // NOPMD - false positive + return Stream.of( + Arguments.of( + map(entry(string("M"), string("Monday"))), + "map:entry(\"M\", \"Monday\")")); + } + + @ParameterizedTest + @MethodSource("provideValues") + void testExpression(@NonNull IMapItem expected, @NonNull String metapath) { + + IItem result = MetapathExpression.compile(metapath) + .evaluateAs(null, MetapathExpression.ResultType.NODE, newDynamicContext()); + assertEquals(expected, result); + } +} diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapFindTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapFindTest.java new file mode 100644 index 000000000..24df92682 --- /dev/null +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapFindTest.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 static gov.nist.secauto.metaschema.core.metapath.TestUtils.array; +import static gov.nist.secauto.metaschema.core.metapath.TestUtils.entry; +import static gov.nist.secauto.metaschema.core.metapath.TestUtils.map; +import static gov.nist.secauto.metaschema.core.metapath.TestUtils.sequence; +import static gov.nist.secauto.metaschema.core.metapath.TestUtils.string; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import gov.nist.secauto.metaschema.core.metapath.ExpressionTestBase; +import gov.nist.secauto.metaschema.core.metapath.MetapathExpression; +import gov.nist.secauto.metaschema.core.metapath.item.IItem; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import edu.umd.cs.findbugs.annotations.NonNull; + +class MapFindTest + extends ExpressionTestBase { + private static final String RESPONSES = "[map{0:'no', 1:'yes'}, map{0:'non', 1:'oui'}," + + " map{0:'nein', 1:('ja', 'doch')}]"; + private static final String INVENTORY = "map{\"name\":\"car\", \"id\":\"QZ123\"," + + " \"parts\": [map{\"name\":\"engine\", \"id\":\"YW678\", \"parts\":[]}]}"; + + private static Stream provideValues() { // NOPMD - false positive + return Stream.of( + Arguments.of( + array(string("no"), string("non"), string("nein")), + "let $responses := " + RESPONSES + " return map:find($responses, 0)"), + Arguments.of( + array(string("yes"), string("oui"), sequence(string("ja"), string("doch"))), + "let $responses := " + RESPONSES + " return map:find($responses, 1)"), + Arguments.of( + array(), + "let $responses := " + RESPONSES + " return map:find($responses, 2)"), + Arguments.of( + array(array(map(entry(string("name"), string("engine")), entry(string("id"), string("YW678")), + entry(string("parts"), array()))), array()), + "let $inventory := " + INVENTORY + " return map:find($inventory, \"parts\")")); + } + + @ParameterizedTest + @MethodSource("provideValues") + void testExpression(@NonNull IItem expected, @NonNull String metapath) { + + IItem result = MetapathExpression.compile(metapath) + .evaluateAs(null, MetapathExpression.ResultType.NODE, newDynamicContext()); + assertEquals(expected, result); + } +} diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapGetTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapGetTest.java new file mode 100644 index 000000000..be8a46f3d --- /dev/null +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapGetTest.java @@ -0,0 +1,70 @@ +/* + * 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 static gov.nist.secauto.metaschema.core.metapath.TestUtils.sequence; +import static gov.nist.secauto.metaschema.core.metapath.TestUtils.string; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import gov.nist.secauto.metaschema.core.metapath.ExpressionTestBase; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.MetapathExpression; +import gov.nist.secauto.metaschema.core.metapath.item.function.LookupTest; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import edu.umd.cs.findbugs.annotations.NonNull; + +class MapGetTest + extends ExpressionTestBase { + + private static Stream provideValues() { // NOPMD - false positive + return Stream.of( + Arguments.of( + sequence(string("Donnerstag")), + "let $week := " + LookupTest.WEEKDAYS_GERMAN + " return map:get($week, 4)"), + Arguments.of( + sequence(), + "let $week := " + LookupTest.WEEKDAYS_GERMAN + " return map:get($week, 9)"), + Arguments.of( + sequence(), + "map:get(map:entry(7,()), 7)")); + } + + @ParameterizedTest + @MethodSource("provideValues") + void testExpression(@NonNull ISequence expected, @NonNull String metapath) { + + ISequence result = MetapathExpression.compile(metapath) + .evaluateAs(null, MetapathExpression.ResultType.SEQUENCE, newDynamicContext()); + assertEquals(expected, result); + } +} diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapKeysTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapKeysTest.java new file mode 100644 index 000000000..b42ef8e40 --- /dev/null +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapKeysTest.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.function.library; + +import static gov.nist.secauto.metaschema.core.metapath.TestUtils.integer; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import gov.nist.secauto.metaschema.core.metapath.ExpressionTestBase; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.MetapathExpression; +import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem; + +import org.junit.jupiter.api.Test; + +import java.util.HashSet; +import java.util.Set; + +class MapKeysTest + extends ExpressionTestBase { + + @Test + void test() { + ISequence result = MetapathExpression.compile("map:keys(map{1:\"yes\", 2:\"no\"})") + .evaluateAs(null, MetapathExpression.ResultType.SEQUENCE); + assert result != null; + + // use a set to allow any ordering of the keys, since we have no control over + // their order + Set keys = new HashSet<>(result); + + assertEquals(Set.of(integer(1), integer(2)), keys); + } +} diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapMergeTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapMergeTest.java new file mode 100644 index 000000000..e4c2101e7 --- /dev/null +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapMergeTest.java @@ -0,0 +1,113 @@ +/* + * 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 static gov.nist.secauto.metaschema.core.metapath.TestUtils.entry; +import static gov.nist.secauto.metaschema.core.metapath.TestUtils.integer; +import static gov.nist.secauto.metaschema.core.metapath.TestUtils.map; +import static gov.nist.secauto.metaschema.core.metapath.TestUtils.sequence; +import static gov.nist.secauto.metaschema.core.metapath.TestUtils.string; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import gov.nist.secauto.metaschema.core.metapath.ExpressionTestBase; +import gov.nist.secauto.metaschema.core.metapath.MetapathExpression; +import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.LookupTest; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import edu.umd.cs.findbugs.annotations.NonNull; + +class MapMergeTest + extends ExpressionTestBase { + private static Stream provideValues() { // NOPMD - false positive + return Stream.of( + Arguments.of( + map(), + "map:merge(())"), + Arguments.of( + map(entry(integer(0), string("no")), entry(integer(1), string("yes"))), + "map:merge((map:entry(0, \"no\"), map:entry(1, \"yes\")))"), + Arguments.of( + map( + entry(integer(0), string("Sonntag")), + entry(integer(1), string("Montag")), + entry(integer(2), string("Dienstag")), + entry(integer(3), string("Mittwoch")), + entry(integer(4), string("Donnerstag")), + entry(integer(5), string("Freitag")), + entry(integer(6), string("Samstag")), + entry(integer(7), string("Unbekannt"))), + "let $week := " + LookupTest.WEEKDAYS_GERMAN + " return map:merge(($week, map{7:\"Unbekannt\"}))"), + Arguments.of( + map( + entry(integer(0), string("Sonntag")), + entry(integer(1), string("Montag")), + entry(integer(2), string("Dienstag")), + entry(integer(3), string("Mittwoch")), + entry(integer(4), string("Donnerstag")), + entry(integer(5), string("Freitag")), + entry(integer(6), string("Sonnabend"))), + "let $week := " + LookupTest.WEEKDAYS_GERMAN + + " return map:merge(($week, map{6:\"Sonnabend\"}), map{\"duplicates\":\"use-last\"})"), + Arguments.of( + map( + entry(integer(0), string("Sonntag")), + entry(integer(1), string("Montag")), + entry(integer(2), string("Dienstag")), + entry(integer(3), string("Mittwoch")), + entry(integer(4), string("Donnerstag")), + entry(integer(5), string("Freitag")), + entry(integer(6), string("Samstag"))), + "let $week := " + LookupTest.WEEKDAYS_GERMAN + + " return map:merge(($week, map{6:\"Sonnabend\"}), map{\"duplicates\":\"use-first\"})"), + Arguments.of( + map( + entry(integer(0), string("Sonntag")), + entry(integer(1), string("Montag")), + entry(integer(2), string("Dienstag")), + entry(integer(3), string("Mittwoch")), + entry(integer(4), string("Donnerstag")), + entry(integer(5), string("Freitag")), + entry(integer(6), sequence(string("Samstag"), string("Sonnabend")))), + "let $week := " + LookupTest.WEEKDAYS_GERMAN + + " return map:merge(($week, map{6:\"Sonnabend\"}), map{\"duplicates\":\"combine\"})")); + } + + @ParameterizedTest + @MethodSource("provideValues") + void testExpression(@NonNull IItem expected, @NonNull String metapath) { + + IItem result = MetapathExpression.compile(metapath) + .evaluateAs(null, MetapathExpression.ResultType.NODE, newDynamicContext()); + assertEquals(expected, result); + } +} diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapPutTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapPutTest.java new file mode 100644 index 000000000..345b48e3f --- /dev/null +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapPutTest.java @@ -0,0 +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.metapath.function.library; + +import static gov.nist.secauto.metaschema.core.metapath.TestUtils.entry; +import static gov.nist.secauto.metaschema.core.metapath.TestUtils.integer; +import static gov.nist.secauto.metaschema.core.metapath.TestUtils.map; +import static gov.nist.secauto.metaschema.core.metapath.TestUtils.string; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import gov.nist.secauto.metaschema.core.metapath.ExpressionTestBase; +import gov.nist.secauto.metaschema.core.metapath.MetapathExpression; +import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.IMapItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.LookupTest; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import edu.umd.cs.findbugs.annotations.NonNull; + +class MapPutTest + extends ExpressionTestBase { + + private static Stream provideValues() { // NOPMD - false positive + return Stream.of( + Arguments.of( + map( + entry(integer(0), string("Sonntag")), + entry(integer(1), string("Montag")), + entry(integer(2), string("Dienstag")), + entry(integer(3), string("Mittwoch")), + entry(integer(4), string("Donnerstag")), + entry(integer(5), string("Freitag")), + entry(integer(6), string("Sonnabend"))), + "let $week := " + LookupTest.WEEKDAYS_GERMAN + " return map:put($week, 6, \"Sonnabend\") "), + Arguments.of( + map( + entry(integer(0), string("Sonntag")), + entry(integer(1), string("Montag")), + entry(integer(2), string("Dienstag")), + entry(integer(3), string("Mittwoch")), + entry(integer(4), string("Donnerstag")), + entry(integer(5), string("Freitag")), + entry(integer(6), string("Samstag")), + entry(integer(-1), string("Unbekannt"))), + "let $week := " + LookupTest.WEEKDAYS_GERMAN + " return map:put($week, -1, \"Unbekannt\")")); + } + + @ParameterizedTest + @MethodSource("provideValues") + void testExpression(@NonNull IMapItem expected, @NonNull String metapath) { + + IItem result = MetapathExpression.compile(metapath) + .evaluateAs(null, MetapathExpression.ResultType.NODE, newDynamicContext()); + assertEquals(expected, result); + } +} diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapRemoveTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapRemoveTest.java new file mode 100644 index 000000000..d2955151e --- /dev/null +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapRemoveTest.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.function.library; + +import static gov.nist.secauto.metaschema.core.metapath.TestUtils.entry; +import static gov.nist.secauto.metaschema.core.metapath.TestUtils.integer; +import static gov.nist.secauto.metaschema.core.metapath.TestUtils.map; +import static gov.nist.secauto.metaschema.core.metapath.TestUtils.string; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import gov.nist.secauto.metaschema.core.metapath.ExpressionTestBase; +import gov.nist.secauto.metaschema.core.metapath.MetapathExpression; +import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.IMapItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.LookupTest; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import edu.umd.cs.findbugs.annotations.NonNull; + +class MapRemoveTest + extends ExpressionTestBase { + + private static Stream provideValues() { // NOPMD - false positive + return Stream.of( + Arguments.of( + map( + entry(integer(0), string("Sonntag")), + entry(integer(1), string("Montag")), + entry(integer(2), string("Dienstag")), + entry(integer(3), string("Mittwoch")), + entry(integer(5), string("Freitag")), + entry(integer(6), string("Samstag"))), + "let $week := " + LookupTest.WEEKDAYS_GERMAN + " return map:remove($week, 4)"), + Arguments.of( + map( + entry(integer(0), string("Sonntag")), + entry(integer(1), string("Montag")), + entry(integer(2), string("Dienstag")), + entry(integer(3), string("Mittwoch")), + entry(integer(4), string("Donnerstag")), + entry(integer(5), string("Freitag")), + entry(integer(6), string("Samstag"))), + "let $week := " + LookupTest.WEEKDAYS_GERMAN + " return map:remove($week, 23)"), + Arguments.of( + map( + entry(integer(1), string("Montag")), + entry(integer(2), string("Dienstag")), + entry(integer(3), string("Mittwoch")), + entry(integer(4), string("Donnerstag")), + entry(integer(5), string("Freitag"))), + "let $week := " + LookupTest.WEEKDAYS_GERMAN + " return map:remove($week, (0, 6 to 7))"), + Arguments.of( + map( + entry(integer(0), string("Sonntag")), + entry(integer(1), string("Montag")), + entry(integer(2), string("Dienstag")), + entry(integer(3), string("Mittwoch")), + entry(integer(4), string("Donnerstag")), + entry(integer(5), string("Freitag")), + entry(integer(6), string("Samstag"))), + "let $week := " + LookupTest.WEEKDAYS_GERMAN + " return map:remove($week, ())")); + } + + @ParameterizedTest + @MethodSource("provideValues") + void testExpression(@NonNull IMapItem expected, @NonNull String metapath) { + + IItem result = MetapathExpression.compile(metapath) + .evaluateAs(null, MetapathExpression.ResultType.NODE, newDynamicContext()); + assertEquals(expected, result); + } +} diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapSizeTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapSizeTest.java new file mode 100644 index 000000000..fa337fbe6 --- /dev/null +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/MapSizeTest.java @@ -0,0 +1,65 @@ +/* + * 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 static gov.nist.secauto.metaschema.core.metapath.TestUtils.integer; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import gov.nist.secauto.metaschema.core.metapath.ExpressionTestBase; +import gov.nist.secauto.metaschema.core.metapath.MetapathExpression; +import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.metapath.item.atomic.IIntegerItem; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import edu.umd.cs.findbugs.annotations.NonNull; + +class MapSizeTest + extends ExpressionTestBase { + private static Stream provideValues() { // NOPMD - false positive + return Stream.of( + Arguments.of( + integer(0), + "map:size(map{})"), + Arguments.of( + integer(2), + "map:size(map{\"true\":1, \"false\":0})")); + } + + @ParameterizedTest + @MethodSource("provideValues") + void testExpression(@NonNull IIntegerItem expected, @NonNull String metapath) { + + IItem result = MetapathExpression.compile(metapath) + .evaluateAs(null, MetapathExpression.ResultType.NODE, newDynamicContext()); + assertEquals(expected, result); + } +} diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/item/function/IArrayItemTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/item/function/IArrayItemTest.java index a83500140..7aa6d9be3 100644 --- a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/item/function/IArrayItemTest.java +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/item/function/IArrayItemTest.java @@ -31,14 +31,10 @@ import static gov.nist.secauto.metaschema.core.metapath.TestUtils.sequence; import static gov.nist.secauto.metaschema.core.metapath.TestUtils.string; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; import gov.nist.secauto.metaschema.core.metapath.ExpressionTestBase; -import gov.nist.secauto.metaschema.core.metapath.ISequence; import gov.nist.secauto.metaschema.core.metapath.MetapathExpression; -import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -89,79 +85,4 @@ void testCurlyConstructor(@NonNull IArrayItem expected, @NonNull String metap assertEquals(expected, result); } - private static Stream functionCallLookupValues() { // NOPMD - false positive - return Stream.of( - // function call lookup - Arguments.of( - sequence(integer(7)), - "[ 1, 2, 5, 7 ](4)"), - Arguments.of( - sequence(array(integer(4), integer(5), integer(6))), - "[ [1, 2, 3], [4, 5, 6]](2)"), - Arguments.of( - sequence(integer(5)), - "[ [1, 2, 3], [4, 5, 6]](2)(2)"), - Arguments.of( - sequence(string("Robert Johnson")), - "[ 'a', 123, \"Robert Johnson\" ](3)"), - Arguments.of( - sequence(integer(27)), - "array { (), (27, 17, 0) }(1)"), - Arguments.of( - sequence(integer(7)), - "[ 1, 2, 5, 7 ](4)")); - } - - @ParameterizedTest - @MethodSource("functionCallLookupValues") - void testFunctionCallLookup(@NonNull ISequence expected, @NonNull String metapath) { - ISequence result = MetapathExpression.compile(metapath) - .evaluateAs(null, MetapathExpression.ResultType.SEQUENCE, newDynamicContext()); - assertEquals(expected, result); - } - - private static Stream postfixLookupValues() { // NOPMD - false positive - return Stream.of( - // postfix lookup - // Arguments.of( - // sequence(string("Jenna")), - // "map { \"first\" : \"Jenna\", \"last\" : \"Scott\" }?first"), - Arguments.of( - sequence(integer(5)), - "[4, 5, 6]?2"), - // Arguments.of( - // sequence(string("Tom"), string("Dick"), string("Harry")), - // "(map {\"first\": \"Tom\"}, map {\"first\": \"Dick\"}, map {\"first\": - // \"Harry\"})?first"), - Arguments.of( - sequence(integer(2), integer(5)), - "([1,2,3], [4,5,6])?2"), - Arguments.of( - sequence(integer(1), integer(2), integer(5), integer(7)), - "[1, 2, 5, 7]?*"), - Arguments.of( - sequence(array(integer(1), integer(2), integer(3)), array(integer(4), integer(5), integer(6))), - "[[1, 2, 3], [4, 5, 6]]?*")); - } - - @ParameterizedTest - @MethodSource("postfixLookupValues") - void testPostfixLookup(@NonNull ISequence expected, @NonNull String metapath) { - ISequence result = MetapathExpression.compile(metapath) - .evaluateAs(null, MetapathExpression.ResultType.SEQUENCE, newDynamicContext()); - assertEquals(expected, result); - } - - @Test - void testUnaryLookupMissingMember() { - ArrayException thrown = assertThrows( - ArrayException.class, - () -> { - ISequence result = MetapathExpression.compile("([1,2,3], [1,2,5], [1,2])[?3 = 5]") - .evaluateAs(null, MetapathExpression.ResultType.SEQUENCE, newDynamicContext()); - assertNotNull(result); - result.safeStream(); - }); - assertEquals(ArrayException.INDEX_OUT_OF_BOUNDS, thrown.getCode()); - } } diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/item/function/LookupTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/item/function/LookupTest.java new file mode 100644 index 000000000..bdff1d6a4 --- /dev/null +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/item/function/LookupTest.java @@ -0,0 +1,183 @@ +/* + * 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.item.function; + +import static gov.nist.secauto.metaschema.core.metapath.TestUtils.array; +import static gov.nist.secauto.metaschema.core.metapath.TestUtils.entry; +import static gov.nist.secauto.metaschema.core.metapath.TestUtils.integer; +import static gov.nist.secauto.metaschema.core.metapath.TestUtils.map; +import static gov.nist.secauto.metaschema.core.metapath.TestUtils.sequence; +import static gov.nist.secauto.metaschema.core.metapath.TestUtils.string; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import gov.nist.secauto.metaschema.core.metapath.ExpressionTestBase; +import gov.nist.secauto.metaschema.core.metapath.ISequence; +import gov.nist.secauto.metaschema.core.metapath.MetapathExpression; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class LookupTest + extends ExpressionTestBase { + + public static final String WEEKDAYS = "map { \"Su\" : \"Sunday\",\"Mo\" : \"Monday\", \"Tu\" : \"Tuesday\"," + + " \"We\" : \"Wednesday\", \"Th\" : \"Thursday\", \"Fr\" : \"Friday\", \"Sa\" : \"Saturday\"}"; + public static final String WEEKDAYS_GERMAN = "map{0:\"Sonntag\", 1:\"Montag\", 2:\"Dienstag\", 3:\"Mittwoch\"," + + " 4:\"Donnerstag\", 5:\"Freitag\", 6:\"Samstag\"}"; + private static final String BOOKS = "map {" + + "\"book\": map {" + + " \"title\": \"Data on the Web\"," + + " \"year\": 2000," + + " \"author\": [" + + " map {" + + " \"last\": \"Abiteboul\"," + + " \"first\": \"Serge\"" + + " }," + + " map {" + + " \"last\": \"Buneman\"," + + " \"first\": \"Peter\"" + + " }," + + " map {" + + " \"last\": \"Suciu\"," + + " \"first\": \"Dan\"" + + " }" + + " ]," + + " \"publisher\": \"Morgan Kaufmann Publishers\"," + + " \"price\": 39.95" + + "}" + + "}"; + + private static Stream functionCallLookupValues() { // NOPMD - false positive + return Stream.of( + // function call lookup + Arguments.of( + sequence(integer(7)), + "[ 1, 2, 5, 7 ](4)"), + Arguments.of( + sequence(array(integer(4), integer(5), integer(6))), + "[ [1, 2, 3], [4, 5, 6]](2)"), + Arguments.of( + sequence(integer(5)), + "[ [1, 2, 3], [4, 5, 6]](2)(2)"), + Arguments.of( + sequence(string("Robert Johnson")), + "[ 'a', 123, \"Robert Johnson\" ](3)"), + Arguments.of( + sequence(integer(27)), + "array { (), (27, 17, 0) }(1)"), + Arguments.of( + sequence(integer(7)), + "[ 1, 2, 5, 7 ](4)"), + Arguments.of( + sequence(string("Donnerstag")), + "let $week := " + WEEKDAYS_GERMAN + " return $week(4)"), + Arguments.of( + sequence(string("Sunday")), + "let $weekdays := " + WEEKDAYS + " return $weekdays(\"Su\")"), + Arguments.of( + sequence(string("Data on the Web")), + "let $b := " + BOOKS + " return $b(\"book\")(\"title\")"), + Arguments.of( + sequence(array( + map( + entry(string("last"), string("Abiteboul")), + entry(string("first"), string("Serge"))), + map( + entry(string("last"), string("Buneman")), + entry(string("first"), string("Peter"))), + map( + entry(string("last"), string("Suciu")), + entry(string("first"), string("Dan"))))), + "let $b := " + BOOKS + " return $b(\"book\")(\"author\")"), + Arguments.of( + sequence(string("Abiteboul")), + "let $b := " + BOOKS + " return $b(\"book\")(\"author\")(1)(\"last\")")); + } + + @ParameterizedTest + @MethodSource("functionCallLookupValues") + void testFunctionCallLookup(@NonNull ISequence expected, @NonNull String metapath) { + ISequence result = MetapathExpression.compile(metapath) + .evaluateAs(null, MetapathExpression.ResultType.SEQUENCE, newDynamicContext()); + assertEquals(expected, result); + } + + private static Stream postfixLookupValues() { // NOPMD - false positive + return Stream.of( + // postfix lookup + Arguments.of( + sequence(string("Jenna")), + "map { \"first\" : \"Jenna\", \"last\" : \"Scott\" }?first"), + Arguments.of( + sequence(integer(5)), + "[4, 5, 6]?2"), + Arguments.of( + sequence(string("Tom"), string("Dick"), string("Harry")), + "(map {\"first\": \"Tom\"}, map {\"first\": \"Dick\"}, map {\"first\":\"Harry\"})?first"), + Arguments.of( + sequence(string("Donnerstag")), + "let $week := " + WEEKDAYS_GERMAN + " return $week?4"), + Arguments.of( + sequence(integer(2), integer(5)), + "([1,2,3], [4,5,6])?2"), + Arguments.of( + sequence(integer(1), integer(2), integer(5), integer(7)), + "[1, 2, 5, 7]?*"), + Arguments.of( + sequence(array(integer(1), integer(2), integer(3)), array(integer(4), integer(5), integer(6))), + "[[1, 2, 3], [4, 5, 6]]?*")); + } + + @ParameterizedTest + @MethodSource("postfixLookupValues") + void testPostfixLookup(@NonNull ISequence expected, @NonNull String metapath) { + ISequence result = MetapathExpression.compile(metapath) + .evaluateAs(null, MetapathExpression.ResultType.SEQUENCE, newDynamicContext()); + assertEquals(expected, result); + } + + @Test + void testUnaryLookupMissingMember() { + ArrayException thrown = assertThrows( + ArrayException.class, + () -> { + ISequence result = MetapathExpression.compile("([1,2,3], [1,2,5], [1,2])[?3 = 5]") + .evaluateAs(null, MetapathExpression.ResultType.SEQUENCE, newDynamicContext()); + assertNotNull(result); + result.safeStream(); + }); + assertEquals(ArrayException.INDEX_OUT_OF_BOUNDS, thrown.getCode()); + } +} diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/annotations/NullJavaTypeAdapter.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/annotations/NullJavaTypeAdapter.java index a140aadca..e29dfad73 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/annotations/NullJavaTypeAdapter.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/annotations/NullJavaTypeAdapter.java @@ -31,6 +31,7 @@ import gov.nist.secauto.metaschema.core.datatype.AbstractDataTypeAdapter; import gov.nist.secauto.metaschema.core.datatype.IDataTypeAdapter; import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem; +import gov.nist.secauto.metaschema.core.metapath.item.function.IMapKey; import gov.nist.secauto.metaschema.databind.model.annotations.NullJavaTypeAdapter.VoidItem; import java.util.List; @@ -119,5 +120,10 @@ public IAnyAtomicItem castAsType(IAnyAtomicItem item) { public int compareTo(IAnyAtomicItem item) { throw new UnsupportedOperationException(NOT_VALID); } + + @Override + public IMapKey asMapKey() { + throw new UnsupportedOperationException(NOT_VALID); + } } }