From 17aec7f0a51ae7e0618771e1d5431fa24bff50f3 Mon Sep 17 00:00:00 2001 From: David Waltermire Date: Thu, 12 Dec 2024 07:49:55 -0500 Subject: [PATCH] Reworked how Metapath expressions are compiled to ensure the static context from their source is used in compilation. Also improved node item, definition, and instance creation for easier use in unit tests. --- core/src/main/antlr4/Metapath10.g4 | 2 +- core/src/main/antlr4/Metapath10Lexer.g4 | 2 +- .../core/mdm/IDMAssemblyNodeItem.java | 29 ++-- .../core/mdm/IDMDefinitionNodeItem.java | 15 ++ .../core/mdm/IDMDocumentNodeItem.java | 12 +- .../metaschema/core/mdm/IDMFieldNodeItem.java | 28 +++- .../metaschema/core/mdm/IDMFlagNodeItem.java | 13 ++ .../metaschema/core/mdm/IDMNodeItem.java | 21 +++ .../mdm/impl/AbstractDMAssemblyNodeItem.java | 44 +----- ...Impl.java => AbstractDMFieldNodeItem.java} | 49 +------ .../mdm/impl/AbstractDMInstanceNodeItem.java | 20 +-- .../mdm/impl/AbstractDMModelNodeItem.java | 55 +++++++ .../core/mdm/impl/AbstractDMNodeItem.java | 33 +++++ ...lyImpl.java => ChildAssemblyNodeItem.java} | 25 +--- .../core/mdm/impl/ChildFieldNodeItem.java | 62 ++++++++ .../{FlagImpl.java => ChildFlagNodeItem.java} | 43 ++++-- .../mdm/impl/DefinitionAssemblyNodeItem.java | 62 ++++++++ .../mdm/impl/DefinitionFieldNodeItem.java | 65 +++++++++ .../core/mdm/impl/DocumentImpl.java | 23 ++- .../mdm/impl/IDMAtomicValuedNodeItem.java | 3 +- .../core/mdm/impl/IDMModelNodeItem.java | 5 +- .../core/mdm/impl/IFeatureChildNodeItem.java | 29 ++++ .../core/metapath/IMetapathExpression.java | 18 +++ .../metapath/antlr/FailingErrorListener.java | 2 +- .../LazyCompilationMetapathExpression.java | 69 +++++++++ .../core/metapath/item/node/package-info.java | 4 +- .../metaschema/core/model/ISource.java | 12 +- ...tConfigurableMessageConstraintBuilder.java | 1 + .../constraint/AbstractConstraintBuilder.java | 7 +- .../AbstractConstraintValidationHandler.java | 4 +- .../AbstractTargetedConstraints.java | 11 +- .../AssemblyTargetedConstraints.java | 3 +- .../DefaultConstraintValidator.java | 7 +- ...xternalConstraintsModulePostProcessor.java | 3 +- .../constraint/FieldTargetedConstraints.java | 3 +- .../constraint/FlagTargetedConstraints.java | 3 +- .../core/model/constraint/IConstraint.java | 9 +- .../model/constraint/IExpectConstraint.java | 9 +- .../core/model/constraint/IIndex.java | 2 +- .../core/model/constraint/IKeyField.java | 12 +- .../constraint/ITargetedConstraints.java | 4 +- ...AbstractConfigurableMessageConstraint.java | 15 +- .../constraint/impl/AbstractConstraint.java | 26 +--- ...AbstractDefinitionTargetedConstraints.java | 3 +- .../impl/AbstractKeyConstraint.java | 3 +- .../impl/DefaultAllowedValuesConstraint.java | 3 +- .../impl/DefaultCardinalityConstraint.java | 3 +- .../impl/DefaultExpectConstraint.java | 27 +--- .../impl/DefaultIndexConstraint.java | 3 +- .../impl/DefaultIndexHasKeyConstraint.java | 3 +- .../constraint/impl/DefaultKeyField.java | 17 +-- .../impl/DefaultMatchesConstraint.java | 3 +- .../impl/DefaultUniqueConstraint.java | 3 +- .../constraint/impl/StaticContextSource.java | 14 +- .../core/model/xml/XmlConstraintLoader.java | 15 +- .../model/xml/XmlMetaConstraintLoader.java | 12 +- .../model/xml/impl/ConstraintXmlSupport.java | 6 +- .../core/model/xml/impl/ModelFactory.java | 38 +++-- .../function/library/FnHasChildrenTest.java | 2 +- .../function/library/FnInnermostTest.java | 2 +- .../function/library/FnLocalNameTest.java | 2 +- .../metapath/function/library/FnNameTest.java | 2 +- .../function/library/FnNamespaceUriTest.java | 2 +- .../function/library/FnOutermostTest.java | 2 +- .../metapath/function/library/FnRootTest.java | 2 +- .../library/impl/MockedDocumentGenerator.java | 25 ++-- .../item/node/DefaultNodeItemFactoryTest.java | 85 +++-------- .../item/node/MockNodeItemFactory.java | 40 ++--- ...ractConfigurableMessageConstraintTest.java | 138 ++++++++++++++++++ .../core/testing/AbstractModelBuilder.java | 89 +++++------ .../core/testing/AssemblyBuilder.java | 84 +++++++---- .../metaschema/core/testing/FieldBuilder.java | 46 +++--- .../metaschema/core/testing/FlagBuilder.java | 45 +++--- .../core/testing/IModuleMockFactory.java | 12 +- .../core/testing/MockedModelTestSupport.java | 33 +---- .../AbstractJMockFactory.java} | 8 +- .../mocking/AbstractMockitoFactory.java | 45 ++++++ .../testing/{ => mocking}/IMockFactory.java | 12 +- .../codegen/impl/AnnotationGenerator.java | 26 +++- .../model/annotations/AllowedValues.java | 2 +- .../databind/model/annotations/Expect.java | 2 +- .../model/impl/ConstraintFactory.java | 34 +++-- .../metaschema/BindingConstraintLoader.java | 40 +++-- .../impl/ConstraintBindingSupport.java | 19 ++- .../schemagen/AbstractGenerationState.java | 2 +- 85 files changed, 1178 insertions(+), 640 deletions(-) create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMDefinitionNodeItem.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMFlagNodeItem.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMNodeItem.java rename core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/{FieldImpl.java => AbstractDMFieldNodeItem.java} (50%) create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/AbstractDMModelNodeItem.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/AbstractDMNodeItem.java rename core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/{AssemblyImpl.java => ChildAssemblyNodeItem.java} (64%) create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/ChildFieldNodeItem.java rename core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/{FlagImpl.java => ChildFlagNodeItem.java} (50%) create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/DefinitionAssemblyNodeItem.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/DefinitionFieldNodeItem.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/IFeatureChildNodeItem.java create mode 100644 core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/LazyCompilationMetapathExpression.java create mode 100644 core/src/test/java/gov/nist/secauto/metaschema/core/model/constraint/impl/AbstractConfigurableMessageConstraintTest.java rename core/src/test/java/gov/nist/secauto/metaschema/core/testing/{MockFactory.java => mocking/AbstractJMockFactory.java} (84%) create mode 100644 core/src/test/java/gov/nist/secauto/metaschema/core/testing/mocking/AbstractMockitoFactory.java rename core/src/test/java/gov/nist/secauto/metaschema/core/testing/{ => mocking}/IMockFactory.java (84%) diff --git a/core/src/main/antlr4/Metapath10.g4 b/core/src/main/antlr4/Metapath10.g4 index ecfb5f43d..1b25cc13f 100644 --- a/core/src/main/antlr4/Metapath10.g4 +++ b/core/src/main/antlr4/Metapath10.g4 @@ -148,7 +148,7 @@ parenthesizeditemtype : OP itemtype CP ; // Error in the spec. EQName also includes acceptable keywords. -eqname : NCName | QName | URIQualifiedName +eqname : URIQualifiedName | NCName | QName | 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 43ebf1b40..879194d59 100644 --- a/core/src/main/antlr4/Metapath10Lexer.g4 +++ b/core/src/main/antlr4/Metapath10Lexer.g4 @@ -117,7 +117,7 @@ DecimalLiteral : '.' FragDigits | FragDigits '.' [0-9]*; DoubleLiteral : ('.' FragDigits | FragDigits ('.' [0-9]*)?) [eE] [+-]? FragDigits; StringLiteral : '"' (~["] | FragEscapeQuot)* '"' | '\'' (~['] | FragEscapeApos)* '\''; URIQualifiedName : BracedURILiteral NCName; -BracedURILiteral : 'Q' '{' [^{}]* '}'; +BracedURILiteral : 'Q' '{' ~[{}]* '}'; // Error in spec: EscapeQuot and EscapeApos are not terminals! fragment FragEscapeQuot : '""'; fragment FragEscapeApos : '\'\''; diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMAssemblyNodeItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMAssemblyNodeItem.java index 09cf2017c..b353f3df1 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMAssemblyNodeItem.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMAssemblyNodeItem.java @@ -5,13 +5,14 @@ package gov.nist.secauto.metaschema.core.mdm; +import gov.nist.secauto.metaschema.core.mdm.impl.DefinitionAssemblyNodeItem; import gov.nist.secauto.metaschema.core.mdm.impl.IDMModelNodeItem; +import gov.nist.secauto.metaschema.core.metapath.StaticContext; import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem; import gov.nist.secauto.metaschema.core.metapath.item.node.IAssemblyNodeItem; import gov.nist.secauto.metaschema.core.model.IAssemblyDefinition; import gov.nist.secauto.metaschema.core.model.IAssemblyInstance; import gov.nist.secauto.metaschema.core.model.IFieldInstance; -import gov.nist.secauto.metaschema.core.model.IResourceLocation; import edu.umd.cs.findbugs.annotations.NonNull; @@ -21,14 +22,27 @@ */ public interface IDMAssemblyNodeItem extends IAssemblyNodeItem, IDMModelNodeItem { + /** + * Create new assembly node item that is detached from a parent node item. + * + * @param definition + * the Metaschema field definition describing the assembly + * @param staticContext + * the atomic field value + * @return the new field node item + */ + @NonNull + static IDMAssemblyNodeItem newInstance( + @NonNull IAssemblyDefinition definition, + @NonNull StaticContext staticContext) { + return new DefinitionAssemblyNodeItem(definition, staticContext); + } + /** * Create and add a new field to the underlying data model. * * @param instance * the Metaschema field instance describing the field - * @param resourceLocation - * information about the location of the field within the containing - * resource * @param value * the atomic field value * @return the new field node item @@ -36,7 +50,6 @@ public interface IDMAssemblyNodeItem @NonNull IDMFieldNodeItem newField( @NonNull IFieldInstance instance, - @NonNull IResourceLocation resourceLocation, @NonNull IAnyAtomicItem value); /** @@ -44,13 +57,9 @@ IDMFieldNodeItem newField( * * @param instance * the Metaschema assembly instance describing the assembly - * @param resourceLocation - * information about the location of the assembly within the containing - * resource * @return the new assembly node item */ @NonNull IDMAssemblyNodeItem newAssembly( - @NonNull IAssemblyInstance instance, - @NonNull IResourceLocation resourceLocation); + @NonNull IAssemblyInstance instance); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMDefinitionNodeItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMDefinitionNodeItem.java new file mode 100644 index 000000000..beaa62b39 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMDefinitionNodeItem.java @@ -0,0 +1,15 @@ +/* + * SPDX-FileCopyrightText: none + * SPDX-License-Identifier: CC0-1.0 + */ + +package gov.nist.secauto.metaschema.core.mdm; + +import gov.nist.secauto.metaschema.core.metapath.item.node.IDefinitionNodeItem; +import gov.nist.secauto.metaschema.core.model.IDefinition; +import gov.nist.secauto.metaschema.core.model.INamedInstance; + +public interface IDMDefinitionNodeItem + extends IDMNodeItem, IDefinitionNodeItem { + +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMDocumentNodeItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMDocumentNodeItem.java index 275b5a341..2b1ff8575 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMDocumentNodeItem.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMDocumentNodeItem.java @@ -8,7 +8,6 @@ import gov.nist.secauto.metaschema.core.mdm.impl.DocumentImpl; import gov.nist.secauto.metaschema.core.metapath.item.node.IDocumentNodeItem; import gov.nist.secauto.metaschema.core.model.IAssemblyDefinition; -import gov.nist.secauto.metaschema.core.model.IResourceLocation; import java.net.URI; @@ -28,21 +27,14 @@ public interface IDMDocumentNodeItem * * @param resource * the base URI of the document resource - * @param resourceLocation - * information about the (intended) location of the document resource * @param rootAssembly * the assembly that is at the root of the node tree for this document - * @param rootAssemblyLocation - * information about the (intended) location of the root assembly - * resource * @return the document node item */ @NonNull static IDMDocumentNodeItem newInstance( @NonNull URI resource, - @NonNull IResourceLocation resourceLocation, - @NonNull IAssemblyDefinition rootAssembly, - @NonNull IResourceLocation rootAssemblyLocation) { - return new DocumentImpl(resource, resourceLocation, rootAssembly, rootAssemblyLocation); + @NonNull IAssemblyDefinition rootAssembly) { + return new DocumentImpl(resource, rootAssembly); } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMFieldNodeItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMFieldNodeItem.java index f26e3680f..4ca01ce71 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMFieldNodeItem.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMFieldNodeItem.java @@ -5,16 +5,40 @@ package gov.nist.secauto.metaschema.core.mdm; +import gov.nist.secauto.metaschema.core.mdm.impl.DefinitionFieldNodeItem; +import gov.nist.secauto.metaschema.core.mdm.impl.IDMAtomicValuedNodeItem; import gov.nist.secauto.metaschema.core.mdm.impl.IDMModelNodeItem; +import gov.nist.secauto.metaschema.core.metapath.StaticContext; +import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem; import gov.nist.secauto.metaschema.core.metapath.item.node.IFieldNodeItem; import gov.nist.secauto.metaschema.core.model.IFieldDefinition; import gov.nist.secauto.metaschema.core.model.IFieldInstance; +import edu.umd.cs.findbugs.annotations.NonNull; + /** * A field node item implementation that is backed by a simple Metaschema * module-based data model. */ public interface IDMFieldNodeItem - extends IFieldNodeItem, IDMModelNodeItem { - // no additional methods + extends IFieldNodeItem, IDMModelNodeItem, IDMAtomicValuedNodeItem { + /** + * Create new field node item that is detached from a parent node item. + * + * @param definition + * the Metaschema field definition describing the field + * @param value + * the field's initial value + * @param staticContext + * the atomic field value + * @return the new field node item + */ + @NonNull + static IDMFieldNodeItem newInstance( + @NonNull IFieldDefinition definition, + @NonNull IAnyAtomicItem value, + @NonNull StaticContext staticContext) { + return new DefinitionFieldNodeItem(definition, value, staticContext); + } + } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMFlagNodeItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMFlagNodeItem.java new file mode 100644 index 000000000..5ee533723 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMFlagNodeItem.java @@ -0,0 +1,13 @@ +/* + * SPDX-FileCopyrightText: none + * SPDX-License-Identifier: CC0-1.0 + */ + +package gov.nist.secauto.metaschema.core.mdm; + +import gov.nist.secauto.metaschema.core.mdm.impl.IDMAtomicValuedNodeItem; +import gov.nist.secauto.metaschema.core.metapath.item.node.IFlagNodeItem; + +public interface IDMFlagNodeItem extends IFlagNodeItem, IDMNodeItem, IDMAtomicValuedNodeItem { + // no additional methods +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMNodeItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMNodeItem.java new file mode 100644 index 000000000..474c1c8c4 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMNodeItem.java @@ -0,0 +1,21 @@ +/* + * SPDX-FileCopyrightText: none + * SPDX-License-Identifier: CC0-1.0 + */ + +package gov.nist.secauto.metaschema.core.mdm; + +import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem; +import gov.nist.secauto.metaschema.core.model.IResourceLocation; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public interface IDMNodeItem extends INodeItem { + /** + * + * @param location + * information about the location of the node within the containing + * resource + */ + void setLocation(@NonNull IResourceLocation location); +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/AbstractDMAssemblyNodeItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/AbstractDMAssemblyNodeItem.java index 6eda28488..02d34035a 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/AbstractDMAssemblyNodeItem.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/AbstractDMAssemblyNodeItem.java @@ -8,12 +8,9 @@ import gov.nist.secauto.metaschema.core.mdm.IDMAssemblyNodeItem; import gov.nist.secauto.metaschema.core.mdm.IDMFieldNodeItem; import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem; -import gov.nist.secauto.metaschema.core.metapath.item.node.AbstractNodeItem; -import gov.nist.secauto.metaschema.core.metapath.item.node.IFlagNodeItem; +import gov.nist.secauto.metaschema.core.model.IAssemblyDefinition; import gov.nist.secauto.metaschema.core.model.IAssemblyInstance; import gov.nist.secauto.metaschema.core.model.IFieldInstance; -import gov.nist.secauto.metaschema.core.model.IFlagInstance; -import gov.nist.secauto.metaschema.core.model.IResourceLocation; import gov.nist.secauto.metaschema.core.qname.IEnhancedQName; import gov.nist.secauto.metaschema.core.util.CollectionUtil; import gov.nist.secauto.metaschema.core.util.ObjectUtils; @@ -28,21 +25,14 @@ import edu.umd.cs.findbugs.annotations.NonNull; public abstract class AbstractDMAssemblyNodeItem - extends AbstractNodeItem + extends AbstractDMModelNodeItem implements IDMAssemblyNodeItem { @NonNull - private final Map flags = new ConcurrentHashMap<>(); - @NonNull private final Map>> modelItems = new ConcurrentHashMap<>(); protected AbstractDMAssemblyNodeItem() { - // nothing to do - } - - @Override - public Object getValue() { - return this; + // only allow extending classes to create instances } @Override @@ -55,26 +45,6 @@ protected String getValueSignature() { return ""; } - @Override - public Collection getFlags() { - return ObjectUtils.notNull(flags.values()); - } - - @Override - public IFlagNodeItem getFlagByName(IEnhancedQName name) { - return flags.get(name); - } - - @Override - public IFlagNodeItem newFlag( - @NonNull IFlagInstance instance, - @NonNull IResourceLocation resourceLocation, - @NonNull IAnyAtomicItem value) { - IFlagNodeItem flag = new FlagImpl(instance, this, resourceLocation, value); - flags.put(instance.getQName(), flag); - return flag; - } - @Override public Collection>> getModelItems() { return ObjectUtils.notNull(modelItems.values()); @@ -87,21 +57,21 @@ public IFlagNodeItem newFlag( } @Override - public IDMFieldNodeItem newField(IFieldInstance instance, IResourceLocation resourceLocation, IAnyAtomicItem value) { + public IDMFieldNodeItem newField(IFieldInstance instance, IAnyAtomicItem value) { List> result = modelItems.computeIfAbsent( instance.getQName(), name -> Collections.synchronizedList(new LinkedList>())); - IDMFieldNodeItem field = new FieldImpl(instance, this, resourceLocation, value); + IDMFieldNodeItem field = new ChildFieldNodeItem(instance, this, value); result.add(field); return field; } @Override - public IDMAssemblyNodeItem newAssembly(IAssemblyInstance instance, IResourceLocation resourceLocation) { + public IDMAssemblyNodeItem newAssembly(IAssemblyInstance instance) { List> result = modelItems.computeIfAbsent( instance.getQName(), name -> Collections.synchronizedList(new LinkedList>())); - IDMAssemblyNodeItem assembly = new AssemblyImpl(instance, this, resourceLocation); + IDMAssemblyNodeItem assembly = new ChildAssemblyNodeItem(instance, this); result.add(assembly); return assembly; } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/FieldImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/AbstractDMFieldNodeItem.java similarity index 50% rename from core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/FieldImpl.java rename to core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/AbstractDMFieldNodeItem.java index 329efcfc9..42cbf87fb 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/FieldImpl.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/AbstractDMFieldNodeItem.java @@ -7,38 +7,24 @@ import gov.nist.secauto.metaschema.core.mdm.IDMFieldNodeItem; import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem; -import gov.nist.secauto.metaschema.core.metapath.item.node.IAssemblyNodeItem; -import gov.nist.secauto.metaschema.core.metapath.item.node.IFlagNodeItem; import gov.nist.secauto.metaschema.core.metapath.item.node.IModelNodeItem; import gov.nist.secauto.metaschema.core.model.IFieldDefinition; import gov.nist.secauto.metaschema.core.model.IFieldInstance; -import gov.nist.secauto.metaschema.core.model.IFlagInstance; -import gov.nist.secauto.metaschema.core.model.IResourceLocation; import gov.nist.secauto.metaschema.core.qname.IEnhancedQName; import gov.nist.secauto.metaschema.core.util.CollectionUtil; -import gov.nist.secauto.metaschema.core.util.ObjectUtils; import java.util.Collection; import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import edu.umd.cs.findbugs.annotations.NonNull; -public class FieldImpl - extends AbstractDMInstanceNodeItem +public abstract class AbstractDMFieldNodeItem + extends AbstractDMModelNodeItem implements IDMFieldNodeItem { @NonNull private IAnyAtomicItem value; - @NonNull - private final Map flags = new ConcurrentHashMap<>(); - public FieldImpl( - @NonNull IFieldInstance instance, - @NonNull IAssemblyNodeItem parent, - @NonNull IResourceLocation resourceLocation, - @NonNull IAnyAtomicItem value) { - super(instance, parent, resourceLocation); + protected AbstractDMFieldNodeItem(@NonNull IAnyAtomicItem value) { this.value = value; } @@ -55,11 +41,6 @@ public void setValue(@NonNull Object value) { this.value = getValueItemType().newItem(value); } - @Override - public Object getValue() { - return toAtomicItem().getValue(); - } - @Override public String stringValue() { return toAtomicItem().asString(); @@ -70,21 +51,6 @@ protected String getValueSignature() { return toAtomicItem().toSignature(); } - @Override - public int getPosition() { - return getParentNodeItem().getModelItemsByName(getQName()).indexOf(this); - } - - @Override - public Collection getFlags() { - return ObjectUtils.notNull(flags.values()); - } - - @Override - public IFlagNodeItem getFlagByName(IEnhancedQName name) { - return flags.get(name); - } - @Override public Collection>> getModelItems() { // no model items @@ -97,13 +63,4 @@ public IFlagNodeItem getFlagByName(IEnhancedQName name) { return CollectionUtil.emptyList(); } - @Override - public IFlagNodeItem newFlag( - @NonNull IFlagInstance instance, - @NonNull IResourceLocation resourceLocation, - @NonNull IAnyAtomicItem value) { - IFlagNodeItem flag = new FlagImpl(instance, this, resourceLocation, value); - flags.put(instance.getQName(), flag); - return flag; - } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/AbstractDMInstanceNodeItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/AbstractDMInstanceNodeItem.java index 6d372c501..f23cb27ed 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/AbstractDMInstanceNodeItem.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/AbstractDMInstanceNodeItem.java @@ -5,32 +5,31 @@ package gov.nist.secauto.metaschema.core.mdm.impl; -import gov.nist.secauto.metaschema.core.metapath.StaticContext; +import gov.nist.secauto.metaschema.core.mdm.IDMNodeItem; import gov.nist.secauto.metaschema.core.metapath.item.node.AbstractInstanceNodeItem; import gov.nist.secauto.metaschema.core.metapath.item.node.IModelNodeItem; -import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem; import gov.nist.secauto.metaschema.core.model.IDefinition; import gov.nist.secauto.metaschema.core.model.IModelDefinition; import gov.nist.secauto.metaschema.core.model.INamedInstance; import gov.nist.secauto.metaschema.core.model.IResourceLocation; import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; public abstract class AbstractDMInstanceNodeItem< D extends IDefinition, I extends INamedInstance, P extends IModelNodeItem> extends AbstractInstanceNodeItem - implements INodeItem { - @NonNull - private final IResourceLocation resourceLocation; + implements IDMNodeItem { + @Nullable + private IResourceLocation resourceLocation; protected AbstractDMInstanceNodeItem( @NonNull I instance, - @NonNull P parent, - @NonNull IResourceLocation resourceLocation) { + @NonNull P parent) { super(instance, parent); - this.resourceLocation = resourceLocation; + this.resourceLocation = null; } @Override @@ -39,7 +38,8 @@ public IResourceLocation getLocation() { } @Override - public StaticContext getStaticContext() { - return getParentNodeItem().getStaticContext(); + public void setLocation(IResourceLocation location) { + this.resourceLocation = location; } + } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/AbstractDMModelNodeItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/AbstractDMModelNodeItem.java new file mode 100644 index 000000000..46820fccb --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/AbstractDMModelNodeItem.java @@ -0,0 +1,55 @@ +/* + * SPDX-FileCopyrightText: none + * SPDX-License-Identifier: CC0-1.0 + */ + +package gov.nist.secauto.metaschema.core.mdm.impl; + +import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem; +import gov.nist.secauto.metaschema.core.metapath.item.node.IFlagNodeItem; +import gov.nist.secauto.metaschema.core.model.IFlagInstance; +import gov.nist.secauto.metaschema.core.model.IModelDefinition; +import gov.nist.secauto.metaschema.core.model.INamedModelInstance; +import gov.nist.secauto.metaschema.core.qname.IEnhancedQName; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public abstract class AbstractDMModelNodeItem + extends AbstractDMNodeItem + implements IDMModelNodeItem { + @NonNull + private final Map flags = new ConcurrentHashMap<>(); + + protected AbstractDMModelNodeItem() { + // only allow extending classes to create instances + } + + @Override + public Object getValue() { + return this; + } + + @Override + public Collection getFlags() { + return ObjectUtils.notNull(flags.values()); + } + + @Override + public IFlagNodeItem getFlagByName(IEnhancedQName name) { + return flags.get(name); + } + + @Override + public IFlagNodeItem newFlag( + @NonNull IFlagInstance instance, + @NonNull IAnyAtomicItem value) { + IFlagNodeItem flag = new ChildFlagNodeItem(instance, this, value); + flags.put(instance.getQName(), flag); + return flag; + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/AbstractDMNodeItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/AbstractDMNodeItem.java new file mode 100644 index 000000000..2782f10ae --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/AbstractDMNodeItem.java @@ -0,0 +1,33 @@ +/* + * SPDX-FileCopyrightText: none + * SPDX-License-Identifier: CC0-1.0 + */ + +package gov.nist.secauto.metaschema.core.mdm.impl; + +import gov.nist.secauto.metaschema.core.mdm.IDMNodeItem; +import gov.nist.secauto.metaschema.core.metapath.item.node.AbstractNodeItem; +import gov.nist.secauto.metaschema.core.model.IResourceLocation; + +import edu.umd.cs.findbugs.annotations.Nullable; + +public abstract class AbstractDMNodeItem + extends AbstractNodeItem + implements IDMNodeItem { + @Nullable + private IResourceLocation resourceLocation = null; + + protected AbstractDMNodeItem() { + // only allow extending classes to create instances + } + + @Override + public IResourceLocation getLocation() { + return resourceLocation; + } + + @Override + public void setLocation(IResourceLocation location) { + this.resourceLocation = location; + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/AssemblyImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/ChildAssemblyNodeItem.java similarity index 64% rename from core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/AssemblyImpl.java rename to core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/ChildAssemblyNodeItem.java index 7c4e047c7..ce51c3c61 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/AssemblyImpl.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/ChildAssemblyNodeItem.java @@ -6,34 +6,24 @@ package gov.nist.secauto.metaschema.core.mdm.impl; import gov.nist.secauto.metaschema.core.mdm.IDMAssemblyNodeItem; -import gov.nist.secauto.metaschema.core.metapath.StaticContext; import gov.nist.secauto.metaschema.core.model.IAssemblyDefinition; import gov.nist.secauto.metaschema.core.model.IAssemblyInstance; -import gov.nist.secauto.metaschema.core.model.IResourceLocation; import edu.umd.cs.findbugs.annotations.NonNull; -public class AssemblyImpl - extends AbstractDMAssemblyNodeItem { +public class ChildAssemblyNodeItem + extends AbstractDMAssemblyNodeItem + implements IFeatureChildNodeItem { @NonNull private final IAssemblyInstance instance; @NonNull private final IDMAssemblyNodeItem parent; - @NonNull - private final IResourceLocation resourceLocation; - public AssemblyImpl( + public ChildAssemblyNodeItem( @NonNull IAssemblyInstance instance, - @NonNull IDMAssemblyNodeItem parent, - @NonNull IResourceLocation resourceLocation) { + @NonNull IDMAssemblyNodeItem parent) { this.instance = instance; this.parent = parent; - this.resourceLocation = resourceLocation; - } - - @Override - public IResourceLocation getLocation() { - return resourceLocation; } @Override @@ -62,9 +52,4 @@ public IAssemblyDefinition getDefinition() { public IAssemblyInstance getInstance() { return instance; } - - @Override - public StaticContext getStaticContext() { - return getParentNodeItem().getStaticContext(); - } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/ChildFieldNodeItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/ChildFieldNodeItem.java new file mode 100644 index 000000000..e3437e829 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/ChildFieldNodeItem.java @@ -0,0 +1,62 @@ +/* + * SPDX-FileCopyrightText: none + * SPDX-License-Identifier: CC0-1.0 + */ + +package gov.nist.secauto.metaschema.core.mdm.impl; + +import gov.nist.secauto.metaschema.core.mdm.IDMFieldNodeItem; +import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem; +import gov.nist.secauto.metaschema.core.metapath.item.node.IAssemblyNodeItem; +import gov.nist.secauto.metaschema.core.model.IFieldDefinition; +import gov.nist.secauto.metaschema.core.model.IFieldInstance; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class ChildFieldNodeItem + extends AbstractDMFieldNodeItem + implements IDMFieldNodeItem, IFeatureChildNodeItem { + @NonNull + private final IFieldInstance instance; + @NonNull + private final IAssemblyNodeItem parent; + + public ChildFieldNodeItem( + @NonNull IFieldInstance instance, + @NonNull IAssemblyNodeItem parent, + @NonNull IAnyAtomicItem value) { + super(value); + this.instance = instance; + this.parent = parent; + } + + @Override + public Object getValue() { + return this; + } + + @Override + public int getPosition() { + return getParentNodeItem().getModelItemsByName(getQName()).indexOf(this); + } + + @Override + public IAssemblyNodeItem getParentNodeItem() { + return parent; + } + + @Override + public IAssemblyNodeItem getParentContentNodeItem() { + return getParentNodeItem(); + } + + @Override + public IFieldDefinition getDefinition() { + return instance.getDefinition(); + } + + @Override + public IFieldInstance getInstance() { + return instance; + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/FlagImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/ChildFlagNodeItem.java similarity index 50% rename from core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/FlagImpl.java rename to core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/ChildFlagNodeItem.java index 1335777a3..c9f4b21c7 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/FlagImpl.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/ChildFlagNodeItem.java @@ -5,30 +5,39 @@ package gov.nist.secauto.metaschema.core.mdm.impl; +import gov.nist.secauto.metaschema.core.mdm.IDMFlagNodeItem; import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem; -import gov.nist.secauto.metaschema.core.metapath.item.node.IFlagNodeItem; -import gov.nist.secauto.metaschema.core.metapath.item.node.IModelNodeItem; +import gov.nist.secauto.metaschema.core.metapath.item.node.AbstractNodeItem; import gov.nist.secauto.metaschema.core.model.IFlagDefinition; import gov.nist.secauto.metaschema.core.model.IFlagInstance; import gov.nist.secauto.metaschema.core.model.IResourceLocation; import edu.umd.cs.findbugs.annotations.NonNull; -public class FlagImpl - extends AbstractDMInstanceNodeItem> - implements IFlagNodeItem { +public class ChildFlagNodeItem + extends AbstractNodeItem + implements IDMFlagNodeItem, IFeatureChildNodeItem> { + @NonNull + private final IFlagInstance instance; + @NonNull + private final IDMModelNodeItem parent; @NonNull private IAnyAtomicItem value; - public FlagImpl( + public ChildFlagNodeItem( @NonNull IFlagInstance instance, - @NonNull IModelNodeItem parent, - @NonNull IResourceLocation resourceLocation, + @NonNull IDMModelNodeItem parent, @NonNull IAnyAtomicItem value) { - super(instance, parent, resourceLocation); + this.instance = instance; + this.parent = parent; this.value = value; } + @Override + public IDMModelNodeItem getParentNodeItem() { + return parent; + } + @Override public IAnyAtomicItem toAtomicItem() { return value; @@ -48,4 +57,20 @@ public String stringValue() { protected String getValueSignature() { return toAtomicItem().toSignature(); } + + @Override + public IFlagDefinition getDefinition() { + return getInstance().getDefinition(); + } + + @Override + public IFlagInstance getInstance() { + return instance; + } + + @Override + public void setLocation(IResourceLocation location) { + // TODO Auto-generated method stub + + } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/DefinitionAssemblyNodeItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/DefinitionAssemblyNodeItem.java new file mode 100644 index 000000000..198897f55 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/DefinitionAssemblyNodeItem.java @@ -0,0 +1,62 @@ +/* + * SPDX-FileCopyrightText: none + * SPDX-License-Identifier: CC0-1.0 + */ + +package gov.nist.secauto.metaschema.core.mdm.impl; + +import gov.nist.secauto.metaschema.core.metapath.StaticContext; +import gov.nist.secauto.metaschema.core.metapath.item.node.IAssemblyNodeItem; +import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem; +import gov.nist.secauto.metaschema.core.model.IAssemblyDefinition; +import gov.nist.secauto.metaschema.core.model.IAssemblyInstance; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class DefinitionAssemblyNodeItem + extends AbstractDMAssemblyNodeItem { + @NonNull + private final IAssemblyDefinition definition; + @NonNull + private final StaticContext staticContext; + + public DefinitionAssemblyNodeItem( + @NonNull IAssemblyDefinition definition, + @NonNull StaticContext staticContext) { + this.definition = definition; + this.staticContext = staticContext; + } + + @Override + public int getPosition() { + return 1; + } + + @Override + public INodeItem getParentNodeItem() { + // always null + return null; + } + + @Override + public IAssemblyNodeItem getParentContentNodeItem() { + // always null + return null; + } + + @Override + public IAssemblyDefinition getDefinition() { + return definition; + } + + @Override + public IAssemblyInstance getInstance() { + // always null + return null; + } + + @Override + public StaticContext getStaticContext() { + return staticContext; + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/DefinitionFieldNodeItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/DefinitionFieldNodeItem.java new file mode 100644 index 000000000..020f453e4 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/DefinitionFieldNodeItem.java @@ -0,0 +1,65 @@ +/* + * SPDX-FileCopyrightText: none + * SPDX-License-Identifier: CC0-1.0 + */ + +package gov.nist.secauto.metaschema.core.mdm.impl; + +import gov.nist.secauto.metaschema.core.metapath.StaticContext; +import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem; +import gov.nist.secauto.metaschema.core.metapath.item.node.IAssemblyNodeItem; +import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem; +import gov.nist.secauto.metaschema.core.model.IFieldDefinition; +import gov.nist.secauto.metaschema.core.model.IFieldInstance; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class DefinitionFieldNodeItem + extends AbstractDMFieldNodeItem { + @NonNull + private final IFieldDefinition definition; + @NonNull + private final StaticContext staticContext; + + public DefinitionFieldNodeItem( + @NonNull IFieldDefinition definition, + @NonNull IAnyAtomicItem value, + @NonNull StaticContext staticContext) { + super(value); + this.definition = definition; + this.staticContext = staticContext; + } + + @Override + public int getPosition() { + return 1; + } + + @Override + public INodeItem getParentNodeItem() { + // always null + return null; + } + + @Override + public IAssemblyNodeItem getParentContentNodeItem() { + // always null + return null; + } + + @Override + public IFieldDefinition getDefinition() { + return definition; + } + + @Override + public IFieldInstance getInstance() { + // always null + return null; + } + + @Override + public StaticContext getStaticContext() { + return staticContext; + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/DocumentImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/DocumentImpl.java index 822233e9a..8625de1c7 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/DocumentImpl.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/DocumentImpl.java @@ -23,22 +23,21 @@ import java.util.List; import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; public class DocumentImpl implements IDMDocumentNodeItem { @NonNull private final RootAssembly root; - @NonNull - private final IResourceLocation resourceLocation; + @Nullable + private IResourceLocation resourceLocation; @NonNull private final ISource source; public DocumentImpl( @NonNull URI resource, - @NonNull IResourceLocation resourceLocation, - @NonNull IAssemblyDefinition root, - @NonNull IResourceLocation assemblyLocation) { - this.root = new RootAssembly(root, assemblyLocation); - this.resourceLocation = resourceLocation; + @NonNull IAssemblyDefinition root) { + this.root = new RootAssembly(root); + this.resourceLocation = null; this.source = ISource.externalSource(resource); } @@ -76,6 +75,10 @@ public IResourceLocation getLocation() { return resourceLocation; } + public void setLocation(@NonNull IResourceLocation location) { + this.resourceLocation = location; + } + @Override public String stringValue() { return ""; @@ -111,14 +114,10 @@ private class RootAssembly implements IDMRootAssemblyNodeItem { @NonNull private final IAssemblyDefinition definition; - @NonNull - private final IResourceLocation resourceLocation; public RootAssembly( - @NonNull IAssemblyDefinition definition, - @NonNull IResourceLocation location) { + @NonNull IAssemblyDefinition definition) { this.definition = definition; - this.resourceLocation = location; } @Override diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/IDMAtomicValuedNodeItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/IDMAtomicValuedNodeItem.java index 6fa3c2af8..91a49af7d 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/IDMAtomicValuedNodeItem.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/IDMAtomicValuedNodeItem.java @@ -5,9 +5,10 @@ package gov.nist.secauto.metaschema.core.mdm.impl; +import gov.nist.secauto.metaschema.core.mdm.IDMNodeItem; import gov.nist.secauto.metaschema.core.metapath.item.node.IAtomicValuedNodeItem; -public interface IDMAtomicValuedNodeItem extends IAtomicValuedNodeItem { +public interface IDMAtomicValuedNodeItem extends IAtomicValuedNodeItem, IDMNodeItem { @Override default String stringValue() { return toAtomicItem().asString(); diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/IDMModelNodeItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/IDMModelNodeItem.java index f0df08fdc..18bc180d8 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/IDMModelNodeItem.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/IDMModelNodeItem.java @@ -5,21 +5,20 @@ package gov.nist.secauto.metaschema.core.mdm.impl; +import gov.nist.secauto.metaschema.core.mdm.IDMDefinitionNodeItem; import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem; import gov.nist.secauto.metaschema.core.metapath.item.node.IFlagNodeItem; import gov.nist.secauto.metaschema.core.metapath.item.node.IModelNodeItem; import gov.nist.secauto.metaschema.core.model.IFlagInstance; import gov.nist.secauto.metaschema.core.model.IModelDefinition; import gov.nist.secauto.metaschema.core.model.INamedModelInstance; -import gov.nist.secauto.metaschema.core.model.IResourceLocation; import edu.umd.cs.findbugs.annotations.NonNull; public interface IDMModelNodeItem - extends IModelNodeItem { + extends IModelNodeItem, IDMDefinitionNodeItem { @NonNull IFlagNodeItem newFlag( @NonNull IFlagInstance instance, - @NonNull IResourceLocation resourceLocation, @NonNull IAnyAtomicItem value); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/IFeatureChildNodeItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/IFeatureChildNodeItem.java new file mode 100644 index 000000000..166ea5f1c --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/IFeatureChildNodeItem.java @@ -0,0 +1,29 @@ +/* + * SPDX-FileCopyrightText: none + * SPDX-License-Identifier: CC0-1.0 + */ + +package gov.nist.secauto.metaschema.core.mdm.impl; + +import gov.nist.secauto.metaschema.core.mdm.IDMNodeItem; +import gov.nist.secauto.metaschema.core.metapath.StaticContext; +import gov.nist.secauto.metaschema.core.metapath.item.node.IModelNodeItem; +import gov.nist.secauto.metaschema.core.model.IModelDefinition; +import gov.nist.secauto.metaschema.core.model.INamedInstance; + +public interface IFeatureChildNodeItem

> + extends IDMNodeItem { + + @Override + P getParentNodeItem(); + + @Override + default P getParentContentNodeItem() { + return getParentNodeItem(); + } + + @Override + default StaticContext getStaticContext() { + return getParentNodeItem().getStaticContext(); + } +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/IMetapathExpression.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/IMetapathExpression.java index 9a2a15799..6673afcc5 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/IMetapathExpression.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/IMetapathExpression.java @@ -8,6 +8,7 @@ import gov.nist.secauto.metaschema.core.metapath.MetapathExpression.ConversionFunction; import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils; import gov.nist.secauto.metaschema.core.metapath.function.library.FnBoolean; +import gov.nist.secauto.metaschema.core.metapath.impl.LazyCompilationMetapathExpression; import gov.nist.secauto.metaschema.core.metapath.item.IItem; import gov.nist.secauto.metaschema.core.metapath.item.ISequence; import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem; @@ -136,6 +137,23 @@ static IMetapathExpression compile(@NonNull String path, @NonNull StaticContext return MetapathExpression.compile(path, staticContext); } + /** + * Gets a new Metapath expression that is compiled on use. + *

+ * Lazy compilation may cause additional {@link MetapathException} errors at + * evaluation time, since compilation errors are not raised until evaluation. + * + * @param path + * the metapath expression + * @param staticContext + * the static evaluation context + * @return the expression object + */ + @NonNull + static IMetapathExpression lazyCompile(@NonNull String path, @NonNull StaticContext staticContext) { + return new LazyCompilationMetapathExpression(path, staticContext); + } + /** * Get the original Metapath expression as a string. * diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/antlr/FailingErrorListener.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/antlr/FailingErrorListener.java index 94dcb57c4..4b9300644 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/antlr/FailingErrorListener.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/antlr/FailingErrorListener.java @@ -22,6 +22,6 @@ public class FailingErrorListener @Override public void syntaxError(Recognizer recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException ex) { - throw new ParseCancellationException("line " + line + ":" + charPositionInLine + " " + msg); + throw new ParseCancellationException("line " + line + ":" + charPositionInLine + " " + msg, ex); } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/LazyCompilationMetapathExpression.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/LazyCompilationMetapathExpression.java new file mode 100644 index 000000000..0336f215b --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/impl/LazyCompilationMetapathExpression.java @@ -0,0 +1,69 @@ +/* + * SPDX-FileCopyrightText: none + * SPDX-License-Identifier: CC0-1.0 + */ + +package gov.nist.secauto.metaschema.core.metapath.impl; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression; +import gov.nist.secauto.metaschema.core.metapath.MetapathException; +import gov.nist.secauto.metaschema.core.metapath.StaticContext; +import gov.nist.secauto.metaschema.core.metapath.item.IItem; +import gov.nist.secauto.metaschema.core.metapath.item.ISequence; +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import edu.umd.cs.findbugs.annotations.NonNull; +import nl.talsmasoftware.lazy4j.Lazy; + +/** + * An implementation of a Metapath expression that is compiled when evaluated. + *

+ * Lazy compilation may cause additional {@link MetapathException} errors at + * evaluation time, since compilation errors are not raised until evaluation. + */ +public class LazyCompilationMetapathExpression implements IMetapathExpression { + @NonNull + private final String path; + @NonNull + private final StaticContext staticContext; + @NonNull + private final Lazy compiledMetapath; + + /** + * Construct a new lazy-compiled Metapath expression. + * + * @param path + * the metapath expression + * @param staticContext + * the static evaluation context + */ + public LazyCompilationMetapathExpression( + @NonNull String path, + @NonNull StaticContext staticContext) { + this.path = path; + this.staticContext = staticContext; + this.compiledMetapath = ObjectUtils.notNull(Lazy.lazy(() -> IMetapathExpression.compile(path, staticContext))); + } + + @Override + public String getPath() { + return path; + } + + @Override + public StaticContext getStaticContext() { + return staticContext; + } + + @NonNull + private IMetapathExpression getCompiledMetapath() { + return ObjectUtils.notNull(compiledMetapath.get()); + } + + @Override + public ISequence evaluate(IItem focus, DynamicContext dynamicContext) { + return getCompiledMetapath().evaluate(focus, dynamicContext); + } + +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/node/package-info.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/node/package-info.java index cda49f921..4d1871000 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/node/package-info.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/item/node/package-info.java @@ -4,8 +4,8 @@ * represented using a Metaschema model. *

* The factory - * {@link gov.nist.secauto.metaschema.core.metapath.item.node.INodeItemFactory} - * can be used to create instances of various node item objects. + * {@link gov.nist.secauto.metaschema.databind.model.impl.INodeItemFactory} can + * be used to create instances of various node item objects. */ package gov.nist.secauto.metaschema.core.metapath.item.node; diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/ISource.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/ISource.java index 2c1c8a76e..ed030343f 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/ISource.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/ISource.java @@ -62,7 +62,8 @@ static ISource externalSource(@NonNull URI location) { return StaticContextSource.instance( StaticContext.builder() .baseUri(location) - .build()); + .build(), + true); } /** @@ -76,15 +77,20 @@ static ISource externalSource(@NonNull URI location) { * @param staticContext * the static Metapath context to use for compiling Metapath * expressions in this source + * @param useCached + * if {@code true} use a previously cached source, otherwise create a + * new one * * @return the source descriptor */ @NonNull - static ISource externalSource(@NonNull StaticContext staticContext) { + static ISource externalSource( + @NonNull StaticContext staticContext, + boolean useCached) { if (staticContext.getBaseUri() == null) { throw new IllegalArgumentException("The static content must define a baseUri identifing the source resource."); } - return StaticContextSource.instance(staticContext); + return StaticContextSource.instance(staticContext, useCached); } /** diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AbstractConfigurableMessageConstraintBuilder.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AbstractConfigurableMessageConstraintBuilder.java index 0d1867d81..452bceace 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AbstractConfigurableMessageConstraintBuilder.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AbstractConfigurableMessageConstraintBuilder.java @@ -24,6 +24,7 @@ public abstract class AbstractConfigurableMessageConstraintBuilder< T extends AbstractConfigurableMessageConstraintBuilder, R extends IConfigurableMessageConstraint> extends AbstractConstraintBuilder { + @Nullable private String message; /** diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AbstractConstraintBuilder.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AbstractConstraintBuilder.java index 1ab6d3fa9..8161dbf0c 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AbstractConstraintBuilder.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AbstractConstraintBuilder.java @@ -7,6 +7,7 @@ import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine; import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline; +import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression; import gov.nist.secauto.metaschema.core.model.IAttributable; import gov.nist.secauto.metaschema.core.model.ISource; import gov.nist.secauto.metaschema.core.model.constraint.IConstraint.Level; @@ -42,7 +43,7 @@ public abstract class AbstractConstraintBuilder< @NonNull private Level level = IConstraint.DEFAULT_LEVEL; @NonNull - private String target = IConstraint.DEFAULT_TARGET_METAPATH; + private IMetapathExpression target = IConstraint.DEFAULT_TARGET_METAPATH; @NonNull private Map> properties = new LinkedHashMap<>(); // NOPMD not thread safe private MarkupMultiline remarks; @@ -131,7 +132,7 @@ public T level(@NonNull Level level) { * @return this builder */ @NonNull - public T target(@NonNull String target) { + public T target(@NonNull IMetapathExpression target) { this.target = target; return getThis(); } @@ -283,7 +284,7 @@ protected Level getLevel() { * @return the target Metapath expression */ @NonNull - protected String getTarget() { + protected IMetapathExpression getTarget() { return target; } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AbstractConstraintValidationHandler.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AbstractConstraintValidationHandler.java index 678c22cab..f5a1f2a20 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AbstractConstraintValidationHandler.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AbstractConstraintValidationHandler.java @@ -87,7 +87,7 @@ protected String newCardinalityMinimumViolationMessage( "The cardinality '%d' is below the required minimum '%d' for items matching '%s'.", testedItems.size(), constraint.getMinOccurs(), - constraint.getTarget())) + constraint.getTarget().getPath())) : constraint.generateMessage(target, dynamicContext); } @@ -284,7 +284,7 @@ protected String newExpectViolationMessage( @NonNull DynamicContext dynamicContext) { return constraint.getMessage() == null ? ObjectUtils.notNull(String.format("Expect constraint '%s' did not match the data at path '%s'", - constraint.getTest(), + constraint.getTest().getPath(), toPath(target))) : constraint.generateMessage(target, dynamicContext); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AbstractTargetedConstraints.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AbstractTargetedConstraints.java index d010cf162..f66dac460 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AbstractTargetedConstraints.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AbstractTargetedConstraints.java @@ -5,6 +5,7 @@ package gov.nist.secauto.metaschema.core.model.constraint; +import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression; import gov.nist.secauto.metaschema.core.model.ISource; import edu.umd.cs.findbugs.annotations.NonNull; @@ -21,7 +22,7 @@ public abstract class AbstractTargetedConstraints @NonNull private final ISource source; @NonNull - private final String targetExpression; + private final IMetapathExpression target; @NonNull private final T constraints; @@ -37,10 +38,10 @@ public abstract class AbstractTargetedConstraints */ protected AbstractTargetedConstraints( @NonNull ISource source, - @NonNull String target, + @NonNull IMetapathExpression target, @NonNull T constraints) { this.source = source; - this.targetExpression = target; + this.target = target; this.constraints = constraints; } @@ -50,8 +51,8 @@ public ISource getSource() { } @Override - public String getTargetExpression() { - return targetExpression; + public IMetapathExpression getTargetExpression() { + return target; } @Override diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AssemblyTargetedConstraints.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AssemblyTargetedConstraints.java index e50f5b592..6d35111d3 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AssemblyTargetedConstraints.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/AssemblyTargetedConstraints.java @@ -5,6 +5,7 @@ package gov.nist.secauto.metaschema.core.model.constraint; +import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression; import gov.nist.secauto.metaschema.core.model.IAssemblyDefinition; import gov.nist.secauto.metaschema.core.model.ISource; import gov.nist.secauto.metaschema.core.model.constraint.impl.AbstractDefinitionTargetedConstraints; @@ -33,7 +34,7 @@ public class AssemblyTargetedConstraints */ public AssemblyTargetedConstraints( @NonNull ISource source, - @NonNull String target, + @NonNull IMetapathExpression target, @NonNull IModelConstrained constraints) { super(source, target, constraints); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/DefaultConstraintValidator.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/DefaultConstraintValidator.java index 0fadac1dc..3f6f414c4 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/DefaultConstraintValidator.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/DefaultConstraintValidator.java @@ -392,7 +392,7 @@ private static String toErrorMessage( String id = constraint.getId(); if (id == null) { builder.append(" targeting the metapath '") - .append(constraint.getTarget()) + .append(constraint.getTarget().getPath()) .append('\''); } else { builder.append(" with id '") @@ -677,10 +677,7 @@ private void validateExpect( @NonNull ISequence targets, @NonNull DynamicContext dynamicContext) { try { - IMetapathExpression metapath = IMetapathExpression.compile( - constraint.getTest(), - dynamicContext.getStaticContext()); - + IMetapathExpression metapath = constraint.getTest(); IConstraintValidationHandler handler = getConstraintValidationHandler(); targets.stream() .forEachOrdered(item -> { diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/ExternalConstraintsModulePostProcessor.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/ExternalConstraintsModulePostProcessor.java index acd3a89ff..b3845b1e3 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/ExternalConstraintsModulePostProcessor.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/ExternalConstraintsModulePostProcessor.java @@ -92,8 +92,7 @@ private static void applyConstraints( @NonNull DynamicContext dynamicContext) { for (ITargetedConstraints targeted : set.getTargetedConstraintsForModule(module)) { // apply targeted constraints - String targetExpression = targeted.getTargetExpression(); - IMetapathExpression metapath = IMetapathExpression.compile(targetExpression, dynamicContext.getStaticContext()); + IMetapathExpression metapath = targeted.getTargetExpression(); ISequence items = metapath.evaluate(moduleItem, dynamicContext); assert items != null; diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/FieldTargetedConstraints.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/FieldTargetedConstraints.java index 4078630ab..3864ac3ff 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/FieldTargetedConstraints.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/FieldTargetedConstraints.java @@ -5,6 +5,7 @@ package gov.nist.secauto.metaschema.core.model.constraint; +import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression; import gov.nist.secauto.metaschema.core.model.IFieldDefinition; import gov.nist.secauto.metaschema.core.model.ISource; import gov.nist.secauto.metaschema.core.model.constraint.impl.AbstractDefinitionTargetedConstraints; @@ -32,7 +33,7 @@ public class FieldTargetedConstraints */ public FieldTargetedConstraints( @NonNull ISource source, - @NonNull String target, + @NonNull IMetapathExpression target, @NonNull IValueConstrained constraints) { super(source, target, constraints); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/FlagTargetedConstraints.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/FlagTargetedConstraints.java index 1981ed572..994642570 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/FlagTargetedConstraints.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/FlagTargetedConstraints.java @@ -5,6 +5,7 @@ package gov.nist.secauto.metaschema.core.model.constraint; +import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression; import gov.nist.secauto.metaschema.core.model.IFlagDefinition; import gov.nist.secauto.metaschema.core.model.ISource; import gov.nist.secauto.metaschema.core.model.constraint.impl.AbstractDefinitionTargetedConstraints; @@ -32,7 +33,7 @@ public class FlagTargetedConstraints */ public FlagTargetedConstraints( @NonNull ISource source, - @NonNull String target, + @NonNull IMetapathExpression target, @NonNull IValueConstrained constraints) { super(source, target, constraints); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/IConstraint.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/IConstraint.java index b70d13e57..473817e5c 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/IConstraint.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/IConstraint.java @@ -7,6 +7,7 @@ import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline; import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression; import gov.nist.secauto.metaschema.core.metapath.MetapathException; import gov.nist.secauto.metaschema.core.metapath.item.ISequence; import gov.nist.secauto.metaschema.core.metapath.item.node.IDefinitionNodeItem; @@ -90,10 +91,10 @@ enum Level { Level DEFAULT_LEVEL = Level.ERROR; /** - * The default target Metapath expression to use if no target is provided. + * The compiled default target Metapath to use if no target is provided. */ @NonNull - String DEFAULT_TARGET_METAPATH = "."; + IMetapathExpression DEFAULT_TARGET_METAPATH = IMetapathExpression.contextNode(); /** * Get a string that identifies the provided constraint using the most specific @@ -111,7 +112,7 @@ static String getConstraintIdentity(@NonNull IConstraint constraint) { } else if (constraint.getFormalName() != null) { identity = String.format("with the formal name '%s'", constraint.getFormalName()); } else { - identity = String.format("targeting '%s'", constraint.getTarget()); + identity = String.format("targeting '%s'", constraint.getTarget().getPath()); } return ObjectUtils.notNull(identity); } @@ -155,7 +156,7 @@ static String getConstraintIdentity(@NonNull IConstraint constraint) { * @return a Metapath expression */ @NonNull - String getTarget(); + IMetapathExpression getTarget(); /** * Based on the provided {@code contextNodeItem}, find all nodes matching the diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/IExpectConstraint.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/IExpectConstraint.java index 16b9e563e..db770ef77 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/IExpectConstraint.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/IExpectConstraint.java @@ -5,6 +5,7 @@ package gov.nist.secauto.metaschema.core.model.constraint; +import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression; import gov.nist.secauto.metaschema.core.model.constraint.impl.DefaultExpectConstraint; import gov.nist.secauto.metaschema.core.util.ObjectUtils; @@ -28,7 +29,7 @@ default Type getType() { * @return the test metapath expression to use */ @NonNull - String getTest(); + IMetapathExpression getTest(); @Override default R accept(IConstraintVisitor visitor, T state) { @@ -50,7 +51,7 @@ static Builder builder() { */ final class Builder extends AbstractConfigurableMessageConstraintBuilder { - private String test; + private IMetapathExpression test; private Builder() { // disable construction @@ -64,7 +65,7 @@ private Builder() { * @return this builder */ @NonNull - public Builder test(@NonNull String test) { + public Builder test(@NonNull IMetapathExpression test) { this.test = test; return this; } @@ -81,7 +82,7 @@ protected void validate() { ObjectUtils.requireNonNull(getTest()); } - private String getTest() { + private IMetapathExpression getTest() { return test; } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/IIndex.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/IIndex.java index 06d4d5ace..45914b155 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/IIndex.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/IIndex.java @@ -160,7 +160,7 @@ private static String buildKeyItem( @NonNull INodeItem item, @NonNull IKeyField keyField, @NonNull DynamicContext dynamicContext) { - IMetapathExpression keyMetapath = keyField.getTargetMetapath(); + IMetapathExpression keyMetapath = keyField.getTarget(); IItem keyItem; try { diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/IKeyField.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/IKeyField.java index 54e91447d..a1155a292 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/IKeyField.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/IKeyField.java @@ -40,7 +40,7 @@ public interface IKeyField { @SuppressWarnings("PMD.ShortMethodName") @NonNull static IKeyField of( - @NonNull String target, + @NonNull IMetapathExpression target, @Nullable Pattern pattern, @Nullable MarkupMultiline remarks, @NonNull ISource source) { @@ -54,15 +54,7 @@ static IKeyField of( * @return the Metapath expression identifying the key value target */ @NonNull - String getTarget(); - - /** - * Get the compiled Metapath expression for the {@link #getTarget()}. - * - * @return the compiled Metapath expression - */ - @NonNull - IMetapathExpression getTargetMetapath(); + IMetapathExpression getTarget(); /** * A pattern to use to retrieve the value. If non-{@code null}, the first diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/ITargetedConstraints.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/ITargetedConstraints.java index e2ca5c5bb..f84edeaeb 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/ITargetedConstraints.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/ITargetedConstraints.java @@ -5,6 +5,7 @@ package gov.nist.secauto.metaschema.core.model.constraint; +import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression; import gov.nist.secauto.metaschema.core.model.IAssemblyDefinition; import gov.nist.secauto.metaschema.core.model.IFieldDefinition; import gov.nist.secauto.metaschema.core.model.IFlagDefinition; @@ -30,8 +31,9 @@ public interface ITargetedConstraints extends IValueConstrained { * * @return the uncompiled Metapath expression */ + // FIXME: rename to getTarget @NonNull - String getTargetExpression(); + IMetapathExpression getTargetExpression(); /** * Apply the constraint to the provided definition. diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/AbstractConfigurableMessageConstraint.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/AbstractConfigurableMessageConstraint.java index 68357c50f..d8debf859 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/AbstractConfigurableMessageConstraint.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/AbstractConfigurableMessageConstraint.java @@ -71,7 +71,7 @@ protected AbstractConfigurableMessageConstraint( @Nullable MarkupLine description, @NonNull ISource source, @NonNull Level level, - @NonNull String target, + @NonNull IMetapathExpression target, @NonNull Map> properties, @Nullable String message, @Nullable MarkupMultiline remarks) { @@ -99,6 +99,19 @@ public String generateMessage(@NonNull INodeItem item, @NonNull DynamicContext c try { IMetapathExpression expr = IMetapathExpression.compile(metapath, context.getStaticContext()); return expr.evaluateAs(item, IMetapathExpression.ResultType.STRING, context); + /* + IMetapathExpression expr = IMetapathExpression.compile( + metapath, + // need to use the static context of the source to resolve prefixes, etc., since + // this is where the message is defined + getSource().getStaticContext()); + return expr.evaluateAs( + item, + IMetapathExpression.ResultType.STRING, + // here we are using the static context of the instance, since this is how + // variables and nodes are resolved. + context); + */ } catch (MetapathException ex) { throw new MetapathException( String.format("Unable to evaluate the message replacement expression '%s' in constraint '%s'. %s", diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/AbstractConstraint.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/AbstractConstraint.java index 66f0f8599..108a9b113 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/AbstractConstraint.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/AbstractConstraint.java @@ -23,7 +23,6 @@ import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; -import nl.talsmasoftware.lazy4j.Lazy; /** * The base class for all constraint implementations. @@ -44,7 +43,7 @@ public abstract class AbstractConstraint implements IConstraint { // NOPMD - int @NonNull private final Map> properties; @NonNull - private final Lazy targetMetapath; + private final IMetapathExpression target; /** * Construct a new Metaschema constraint. @@ -73,7 +72,7 @@ protected AbstractConstraint( @Nullable MarkupLine description, @NonNull ISource source, @NonNull Level level, - @NonNull String target, + @NonNull IMetapathExpression target, @NonNull Map> properties, @Nullable MarkupMultiline remarks) { Objects.requireNonNull(target); @@ -84,10 +83,7 @@ protected AbstractConstraint( this.level = ObjectUtils.requireNonNull(level, "level"); this.properties = properties; this.remarks = remarks; - this.targetMetapath = ObjectUtils.notNull( - Lazy.lazy(() -> IMetapathExpression.compile( - target, - source.getStaticContext()))); + this.target = target; } @Override @@ -117,8 +113,8 @@ public Level getLevel() { } @Override - public final String getTarget() { - return getTargetMetapath().getPath(); + public final IMetapathExpression getTarget() { + return target; } @Override @@ -131,21 +127,11 @@ public MarkupMultiline getRemarks() { return remarks; } - /** - * Get the compiled Metapath expression for the target. - * - * @return the compiled Metapath expression - */ - @NonNull - public final IMetapathExpression getTargetMetapath() { - return ObjectUtils.notNull(targetMetapath.get()); - } - @Override @NonNull public ISequence> matchTargets( @NonNull IDefinitionNodeItem item, @NonNull DynamicContext dynamicContext) { - return item.hasValue() ? getTargetMetapath().evaluate(item, dynamicContext) : ISequence.empty(); + return item.hasValue() ? getTarget().evaluate(item, dynamicContext) : ISequence.empty(); } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/AbstractDefinitionTargetedConstraints.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/AbstractDefinitionTargetedConstraints.java index 853607051..2f19a4a27 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/AbstractDefinitionTargetedConstraints.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/AbstractDefinitionTargetedConstraints.java @@ -5,6 +5,7 @@ package gov.nist.secauto.metaschema.core.model.constraint.impl; +import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression; import gov.nist.secauto.metaschema.core.model.IAssemblyDefinition; import gov.nist.secauto.metaschema.core.model.IDefinition; import gov.nist.secauto.metaschema.core.model.IFieldDefinition; @@ -45,7 +46,7 @@ public abstract class AbstractDefinitionTargetedConstraints< */ protected AbstractDefinitionTargetedConstraints( @NonNull ISource source, - @NonNull String target, + @NonNull IMetapathExpression target, @NonNull S constraints) { super(source, target, constraints); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/AbstractKeyConstraint.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/AbstractKeyConstraint.java index c7fcb1647..daa6e1550 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/AbstractKeyConstraint.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/AbstractKeyConstraint.java @@ -7,6 +7,7 @@ import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine; import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline; +import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression; import gov.nist.secauto.metaschema.core.model.IAttributable; import gov.nist.secauto.metaschema.core.model.ISource; import gov.nist.secauto.metaschema.core.model.constraint.ConstraintInitializationException; @@ -61,7 +62,7 @@ protected AbstractKeyConstraint( @Nullable MarkupLine description, @NonNull ISource source, @NonNull Level level, - @NonNull String target, + @NonNull IMetapathExpression target, @NonNull Map> properties, @NonNull List keyFields, @Nullable String message, diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultAllowedValuesConstraint.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultAllowedValuesConstraint.java index 3b5650a08..f84944154 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultAllowedValuesConstraint.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultAllowedValuesConstraint.java @@ -7,6 +7,7 @@ import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine; import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline; +import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression; import gov.nist.secauto.metaschema.core.model.IAttributable; import gov.nist.secauto.metaschema.core.model.ISource; import gov.nist.secauto.metaschema.core.model.constraint.IAllowedValue; @@ -70,7 +71,7 @@ public DefaultAllowedValuesConstraint( // NOPMD necessary @Nullable MarkupLine description, @NonNull ISource source, @NonNull Level level, - @NonNull String target, + @NonNull IMetapathExpression target, @NonNull Map> properties, @NonNull Map allowedValues, boolean allowedOther, diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultCardinalityConstraint.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultCardinalityConstraint.java index 3db8a01a4..478db95c6 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultCardinalityConstraint.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultCardinalityConstraint.java @@ -7,6 +7,7 @@ import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine; import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline; +import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression; import gov.nist.secauto.metaschema.core.model.IAttributable; import gov.nist.secauto.metaschema.core.model.ISource; import gov.nist.secauto.metaschema.core.model.constraint.ConstraintInitializationException; @@ -70,7 +71,7 @@ public DefaultCardinalityConstraint( @Nullable MarkupLine description, @NonNull ISource source, @NonNull Level level, - @NonNull String target, + @NonNull IMetapathExpression target, @NonNull Map> properties, @Nullable Integer minOccurs, @Nullable Integer maxOccurs, diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultExpectConstraint.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultExpectConstraint.java index a1c00f953..744bdd46f 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultExpectConstraint.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultExpectConstraint.java @@ -12,14 +12,12 @@ import gov.nist.secauto.metaschema.core.model.IAttributable; import gov.nist.secauto.metaschema.core.model.ISource; import gov.nist.secauto.metaschema.core.model.constraint.IExpectConstraint; -import gov.nist.secauto.metaschema.core.util.ObjectUtils; import java.util.Map; import java.util.Set; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; -import nl.talsmasoftware.lazy4j.Lazy; /** * Represents an expect constraint. @@ -31,7 +29,7 @@ public final class DefaultExpectConstraint extends AbstractConfigurableMessageConstraint implements IExpectConstraint { @NonNull - private final Lazy testMetapath; + private final IMetapathExpression test; /** * Construct a new expect constraint. @@ -66,30 +64,17 @@ public DefaultExpectConstraint( @Nullable MarkupLine description, @NonNull ISource source, @NonNull Level level, - @NonNull String target, + @NonNull IMetapathExpression target, @NonNull Map> properties, - @NonNull String test, + @NonNull IMetapathExpression test, @Nullable String message, @Nullable MarkupMultiline remarks) { super(id, formalName, description, source, level, target, properties, message, remarks); - this.testMetapath = ObjectUtils.notNull( - Lazy.lazy(() -> IMetapathExpression.compile( - test, - source.getStaticContext()))); - } - - /** - * Get the compiled Metapath expression for the test. - * - * @return the compiled Metapath expression - */ - @NonNull - public IMetapathExpression getTestMetapath() { - return ObjectUtils.notNull(testMetapath.get()); + this.test = test; } @Override - public String getTest() { - return getTestMetapath().getPath(); + public IMetapathExpression getTest() { + return test; } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultIndexConstraint.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultIndexConstraint.java index c5fb4a241..7a8e6ee74 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultIndexConstraint.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultIndexConstraint.java @@ -7,6 +7,7 @@ import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine; import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline; +import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression; import gov.nist.secauto.metaschema.core.model.IAttributable; import gov.nist.secauto.metaschema.core.model.ISource; import gov.nist.secauto.metaschema.core.model.constraint.ConstraintInitializationException; @@ -69,7 +70,7 @@ public DefaultIndexConstraint( @Nullable MarkupLine description, @NonNull ISource source, @NonNull Level level, - @NonNull String target, + @NonNull IMetapathExpression target, @NonNull Map> properties, @NonNull String name, @NonNull List keyFields, diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultIndexHasKeyConstraint.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultIndexHasKeyConstraint.java index 3ac34f5d6..1303764b7 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultIndexHasKeyConstraint.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultIndexHasKeyConstraint.java @@ -7,6 +7,7 @@ import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine; import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline; +import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression; import gov.nist.secauto.metaschema.core.model.IAttributable; import gov.nist.secauto.metaschema.core.model.ISource; import gov.nist.secauto.metaschema.core.model.constraint.ConstraintInitializationException; @@ -67,7 +68,7 @@ public DefaultIndexHasKeyConstraint( @Nullable MarkupLine description, @NonNull ISource source, @NonNull Level level, - @NonNull String target, + @NonNull IMetapathExpression target, @NonNull Map> properties, @NonNull String indexName, @NonNull List keyFields, diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultKeyField.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultKeyField.java index 9be2c9feb..ac29482c3 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultKeyField.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultKeyField.java @@ -9,20 +9,18 @@ import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression; import gov.nist.secauto.metaschema.core.model.ISource; import gov.nist.secauto.metaschema.core.model.constraint.IKeyField; -import gov.nist.secauto.metaschema.core.util.ObjectUtils; import java.util.regex.Pattern; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; -import nl.talsmasoftware.lazy4j.Lazy; public class DefaultKeyField implements IKeyField { @Nullable private final Pattern pattern; @NonNull - private final Lazy target; + private final IMetapathExpression target; @Nullable private final MarkupMultiline remarks; @@ -40,12 +38,12 @@ public class DefaultKeyField implements IKeyField { * the descriptor for the resource containing the constraint */ public DefaultKeyField( - @NonNull String target, + @NonNull IMetapathExpression target, @Nullable Pattern pattern, @Nullable MarkupMultiline remarks, @NonNull ISource source) { this.pattern = pattern; - this.target = ObjectUtils.notNull(Lazy.lazy(() -> IMetapathExpression.compile(target, source.getStaticContext()))); + this.target = target; this.remarks = remarks; } @@ -55,13 +53,8 @@ public Pattern getPattern() { } @Override - public String getTarget() { - return getTargetMetapath().getPath(); - } - - @Override - public IMetapathExpression getTargetMetapath() { - return ObjectUtils.notNull(target.get()); + public IMetapathExpression getTarget() { + return target; } @Override diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultMatchesConstraint.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultMatchesConstraint.java index 952769386..0f581c8e5 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultMatchesConstraint.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultMatchesConstraint.java @@ -8,6 +8,7 @@ import gov.nist.secauto.metaschema.core.datatype.IDataTypeAdapter; import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine; import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline; +import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression; import gov.nist.secauto.metaschema.core.model.IAttributable; import gov.nist.secauto.metaschema.core.model.ISource; import gov.nist.secauto.metaschema.core.model.constraint.ConstraintInitializationException; @@ -68,7 +69,7 @@ public DefaultMatchesConstraint( @Nullable MarkupLine description, @NonNull ISource source, @NonNull Level level, - @NonNull String target, + @NonNull IMetapathExpression target, @NonNull Map> properties, @Nullable Pattern pattern, @Nullable IDataTypeAdapter dataType, diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultUniqueConstraint.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultUniqueConstraint.java index 4293feb1b..1bd9f3f23 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultUniqueConstraint.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/DefaultUniqueConstraint.java @@ -7,6 +7,7 @@ import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine; import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline; +import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression; import gov.nist.secauto.metaschema.core.model.IAttributable; import gov.nist.secauto.metaschema.core.model.ISource; import gov.nist.secauto.metaschema.core.model.constraint.IKeyField; @@ -60,7 +61,7 @@ public DefaultUniqueConstraint( @Nullable MarkupLine description, @NonNull ISource source, @NonNull Level level, - @NonNull String target, + @NonNull IMetapathExpression target, @NonNull Map> properties, @NonNull List keyFields, @Nullable String message, diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/StaticContextSource.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/StaticContextSource.java index 0e0262039..601aa438b 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/StaticContextSource.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/constraint/impl/StaticContextSource.java @@ -38,10 +38,22 @@ public final class StaticContextSource implements ISource { * @param staticContext * the static Metapath context to use for compiling Metapath * expressions in this source + * @param useCached + * if {@code true} use a previously cached source, otherwise create a + * new one * @return the source */ @NonNull - public static ISource instance(@NonNull StaticContext staticContext) { + public static ISource instance( + @NonNull StaticContext staticContext, + boolean useCached) { + return useCached + ? retrieveFromCache(staticContext) + : new StaticContextSource(staticContext); + } + + @NonNull + private static StaticContextSource retrieveFromCache(@NonNull StaticContext staticContext) { SOURCE_LOCK.lock(); try { return ObjectUtils.notNull(sources.computeIfAbsent( diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/XmlConstraintLoader.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/XmlConstraintLoader.java index 35b0a3f37..47bcd0fb9 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/XmlConstraintLoader.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/XmlConstraintLoader.java @@ -5,6 +5,7 @@ package gov.nist.secauto.metaschema.core.model.xml; +import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression; import gov.nist.secauto.metaschema.core.metapath.MetapathException; import gov.nist.secauto.metaschema.core.metapath.StaticContext; import gov.nist.secauto.metaschema.core.model.AbstractLoader; @@ -173,7 +174,7 @@ protected List parseScopedConstraints( builder.useWildcardWhenNamespaceNotDefaulted(true); - ISource source = ISource.externalSource(resource); + ISource source = ISource.externalSource(builder.build(), false); for (Scope scope : constraints.getScopeList()) { assert scope != null; @@ -214,7 +215,9 @@ private static void handleScopedAssembly( state.getRight().add(new AssemblyTargetedConstraints( source, - ObjectUtils.requireNonNull(assembly.getTarget()), + IMetapathExpression.lazyCompile( + ObjectUtils.requireNonNull(assembly.getTarget()), + source.getStaticContext()), constraints)); } @@ -229,7 +232,9 @@ private static void handleScopedField( // NOPMD false positive state.getRight().add(new FieldTargetedConstraints( source, - ObjectUtils.requireNonNull(field.getTarget()), + IMetapathExpression.lazyCompile( + ObjectUtils.requireNonNull(field.getTarget()), + source.getStaticContext()), constraints)); } @@ -244,7 +249,9 @@ private static void handleScopedFlag( // NOPMD false positive state.getRight().add(new FlagTargetedConstraints( source, - ObjectUtils.requireNonNull(flag.getTarget()), + IMetapathExpression.lazyCompile( + ObjectUtils.requireNonNull(flag.getTarget()), + source.getStaticContext()), constraints)); } } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/XmlMetaConstraintLoader.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/XmlMetaConstraintLoader.java index f12b8578b..f3e0b70d0 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/XmlMetaConstraintLoader.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/XmlMetaConstraintLoader.java @@ -5,6 +5,7 @@ package gov.nist.secauto.metaschema.core.model.xml; +import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression; import gov.nist.secauto.metaschema.core.metapath.StaticContext; import gov.nist.secauto.metaschema.core.model.AbstractLoader; import gov.nist.secauto.metaschema.core.model.IAssemblyDefinition; @@ -66,7 +67,7 @@ protected List parseResource(URI resource, Deque visitedRes ObjectUtils.notNull(binding.getPrefix()), ObjectUtils.notNull(binding.getUri()))); builder.useWildcardWhenNamespaceNotDefaulted(true); - ISource source = ISource.externalSource(resource); + ISource source = ISource.externalSource(builder.build(), true); List targetedConstraints = ObjectUtils.notNull(constraints.getContextList().stream() .flatMap(context -> parseContext(ObjectUtils.notNull(context), null, source).getTargetedConstraints().stream()) @@ -151,7 +152,12 @@ public Context( public List getTargetedConstraints() { return Stream.concat( getMetapaths().stream() - .map(metapath -> new MetaTargetedContraints(source, ObjectUtils.notNull(metapath), constraints)), + .map(metapath -> new MetaTargetedContraints( + source, + IMetapathExpression.lazyCompile( + ObjectUtils.requireNonNull(metapath), + source.getStaticContext()), + constraints)), childContexts.stream() .flatMap(child -> child.getTargetedConstraints().stream())) .collect(Collectors.toList()); @@ -172,7 +178,7 @@ private static class MetaTargetedContraints protected MetaTargetedContraints( @NonNull ISource source, - @NonNull String target, + @NonNull IMetapathExpression target, @NonNull IModelConstrained constraints) { super(source, target, constraints); } diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/ConstraintXmlSupport.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/ConstraintXmlSupport.java index bb5aa223c..b03298c89 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/ConstraintXmlSupport.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/ConstraintXmlSupport.java @@ -438,7 +438,7 @@ public Void visitAllowedValues(IAllowedValuesConstraint constraint, DefineAssemb if (Boolean.compare(IAllowedValuesConstraint.ALLOW_OTHER_DEFAULT, constraint.isAllowedOther()) != 0) { bean.setAllowOther(constraint.isAllowedOther()); } - bean.setTarget(constraint.getTarget()); + bean.setTarget(constraint.getTarget().getPath()); bean.setExtensible(constraint.getExtensible()); for (Map.Entry entry : constraint.getAllowedValues().entrySet()) { @@ -494,7 +494,7 @@ public Void visitExpectConstraint(IExpectConstraint constraint, DefineAssemblyCo assert bean != null; applyCommonValues(constraint, bean); - bean.setTest(constraint.getTest()); + bean.setTest(constraint.getTest().getPath()); String message = constraint.getMessage(); if (message != null) { @@ -550,7 +550,7 @@ private static void applyKeyField(@NonNull IKeyField keyField, @NonNull KeyField bean.setPattern(pattern); } - bean.setTarget(keyField.getTarget()); + bean.setTarget(keyField.getTarget().getPath()); MarkupMultiline remarks = keyField.getRemarks(); if (remarks != null) { diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/ModelFactory.java b/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/ModelFactory.java index e13724971..fcb77ee45 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/ModelFactory.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/model/xml/impl/ModelFactory.java @@ -6,6 +6,7 @@ package gov.nist.secauto.metaschema.core.model.xml.impl; import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline; +import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression; import gov.nist.secauto.metaschema.core.model.IAttributable; import gov.nist.secauto.metaschema.core.model.ISource; import gov.nist.secauto.metaschema.core.model.constraint.AbstractConstraintBuilder; @@ -63,8 +64,10 @@ private ModelFactory() { } @NonNull - private static String target(@Nullable String target) { - return target == null ? IConstraint.DEFAULT_TARGET_METAPATH : target; + private static IMetapathExpression metapath(@Nullable String target, @NonNull ISource source) { + return target == null + ? IConstraint.DEFAULT_TARGET_METAPATH + : IMetapathExpression.lazyCompile(target, source.getStaticContext()); } @NonNull @@ -145,7 +148,7 @@ private static Map toAllowedValues( public static IAllowedValuesConstraint newAllowedValuesConstraint( @NonNull TargetedAllowedValuesConstraintType xmlObject, @NonNull ISource source) { - return newAllowedValuesConstraint(xmlObject, target(xmlObject.getTarget()), source); + return newAllowedValuesConstraint(xmlObject, metapath(xmlObject.getTarget(), source), source); } /** @@ -167,7 +170,7 @@ public static IAllowedValuesConstraint newAllowedValuesConstraint( @NonNull private static IAllowedValuesConstraint newAllowedValuesConstraint( @NonNull AllowedValuesType xmlObject, - @NonNull String target, + @NonNull IMetapathExpression target, @NonNull ISource source) { IAllowedValuesConstraint.Builder builder = IAllowedValuesConstraint.builder(); @@ -192,7 +195,7 @@ private static IAllowedValuesConstraint newAllowedValuesConstraint( @NonNull private static > T applyToBuilder( @NonNull ConstraintType xmlObject, - @NonNull String target, + @NonNull IMetapathExpression target, @NonNull ISource source, @NonNull T builder) { @@ -218,7 +221,7 @@ private static IAllowedValuesConstraint newAllowedValuesConstraint( public static IMatchesConstraint newMatchesConstraint( @NonNull TargetedMatchesConstraintType xmlObject, @NonNull ISource source) { - return newMatchesConstraint(xmlObject, target(xmlObject.getTarget()), source); + return newMatchesConstraint(xmlObject, metapath(xmlObject.getTarget(), source), source); } /** @@ -240,7 +243,7 @@ public static IMatchesConstraint newMatchesConstraint( @NonNull private static IMatchesConstraint newMatchesConstraint( @NonNull MatchesConstraintType xmlObject, - @NonNull String target, + @NonNull IMetapathExpression target, @NonNull ISource source) { IMatchesConstraint.Builder builder = IMatchesConstraint.builder(); @@ -270,7 +273,7 @@ private static void buildKeyFields( @NonNull ISource source) { for (KeyConstraintType.KeyField xmlKeyField : xmlObject.getKeyFieldList()) { IKeyField keyField = IKeyField.of( - ObjectUtils.requireNonNull(xmlKeyField.getTarget()), + metapath(ObjectUtils.requireNonNull(xmlKeyField.getTarget()), source), xmlKeyField.isSetPattern() ? xmlKeyField.getPattern() : null, // NOPMD - intentional xmlKeyField.isSetRemarks() ? remarks(ObjectUtils.notNull(xmlKeyField.getRemarks())) : null, source); @@ -293,7 +296,7 @@ public static IUniqueConstraint newUniqueConstraint( @NonNull ISource source) { IUniqueConstraint.Builder builder = IUniqueConstraint.builder(); - applyToBuilder(xmlObject, target(xmlObject.getTarget()), source, builder); + applyToBuilder(xmlObject, metapath(xmlObject.getTarget(), source), source, builder); if (xmlObject.isSetMessage()) { builder.message(ObjectUtils.notNull(xmlObject.getMessage())); @@ -323,7 +326,7 @@ public static IIndexConstraint newIndexConstraint( @NonNull ISource source) { IIndexConstraint.Builder builder = IIndexConstraint.builder(ObjectUtils.requireNonNull(xmlObject.getName())); - applyToBuilder(xmlObject, target(xmlObject.getTarget()), source, builder); + applyToBuilder(xmlObject, metapath(xmlObject.getTarget(), source), source, builder); if (xmlObject.isSetMessage()) { builder.message(ObjectUtils.notNull(xmlObject.getMessage())); @@ -351,7 +354,7 @@ public static IIndexConstraint newIndexConstraint( public static IIndexHasKeyConstraint newIndexHasKeyConstraint( @NonNull TargetedIndexHasKeyConstraintType xmlObject, @NonNull ISource source) { - return newIndexHasKeyConstraint(xmlObject, target(xmlObject.getTarget()), source); + return newIndexHasKeyConstraint(xmlObject, metapath(xmlObject.getTarget(), source), source); } /** @@ -373,7 +376,7 @@ public static IIndexHasKeyConstraint newIndexHasKeyConstraint( @NonNull private static IIndexHasKeyConstraint newIndexHasKeyConstraint( @NonNull IndexHasKeyConstraintType xmlObject, - @NonNull String target, + @NonNull IMetapathExpression target, @NonNull ISource source) { IIndexHasKeyConstraint.Builder builder = IIndexHasKeyConstraint.builder(ObjectUtils.requireNonNull(xmlObject.getName())); @@ -406,7 +409,7 @@ private static IIndexHasKeyConstraint newIndexHasKeyConstraint( public static IExpectConstraint newExpectConstraint( @NonNull TargetedExpectConstraintType xmlObject, @NonNull ISource source) { - return newExpectConstraint(xmlObject, target(xmlObject.getTarget()), source); + return newExpectConstraint(xmlObject, metapath(xmlObject.getTarget(), source), source); } /** @@ -428,7 +431,7 @@ public static IExpectConstraint newExpectConstraint( @NonNull private static IExpectConstraint newExpectConstraint( @NonNull ExpectConstraintType xmlObject, - @NonNull String target, + @NonNull IMetapathExpression target, @NonNull ISource source) { IExpectConstraint.Builder builder = IExpectConstraint.builder(); @@ -443,7 +446,10 @@ private static IExpectConstraint newExpectConstraint( builder.remarks(remarks(ObjectUtils.notNull(xmlObject.getRemarks()))); } - builder.test(ObjectUtils.requireNonNull(xmlObject.getTest())); + builder.test( + IMetapathExpression.lazyCompile( + ObjectUtils.requireNonNull(xmlObject.getTest()), + source.getStaticContext())); return builder.build(); } @@ -464,7 +470,7 @@ public static ICardinalityConstraint newCardinalityConstraint( ICardinalityConstraint.Builder builder = ICardinalityConstraint.builder(); - applyToBuilder(xmlObject, target(xmlObject.getTarget()), source, builder); + applyToBuilder(xmlObject, metapath(xmlObject.getTarget(), source), source, builder); if (xmlObject.isSetMessage()) { builder.message(ObjectUtils.notNull(xmlObject.getMessage())); diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnHasChildrenTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnHasChildrenTest.java index ad89574e0..76e94165c 100644 --- a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnHasChildrenTest.java +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnHasChildrenTest.java @@ -62,7 +62,7 @@ private static Stream provideValues() { // NOPMD - false positive void test(boolean expected, @NonNull String metapath) { DynamicContext dynamicContext = newDynamicContext(); - INodeItem node = MockedDocumentGenerator.generateDocumentNodeItem(getContext()); + INodeItem node = MockedDocumentGenerator.generateDocumentNodeItem(); Boolean result = IMetapathExpression.compile(metapath, dynamicContext.getStaticContext()) .evaluateAs(node, IMetapathExpression.ResultType.BOOLEAN, dynamicContext); assertEquals(expected, result); diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnInnermostTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnInnermostTest.java index 17746b27d..ffa773f76 100644 --- a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnInnermostTest.java +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnInnermostTest.java @@ -52,7 +52,7 @@ private static Stream provideValues() { // NOPMD - false positive @MethodSource("provideValues") void test(@NonNull String expectedValueMetapath, @NonNull String actualValuesMetapath) { DynamicContext dynamicContext = newDynamicContext(); - INodeItem node = MockedDocumentGenerator.generateDocumentNodeItem(getContext()); + INodeItem node = MockedDocumentGenerator.generateDocumentNodeItem(); ISequence expected = IMetapathExpression.compile(expectedValueMetapath, dynamicContext.getStaticContext()) diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnLocalNameTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnLocalNameTest.java index 6a0647477..375d88863 100644 --- a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnLocalNameTest.java +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnLocalNameTest.java @@ -66,7 +66,7 @@ void test(@Nullable IEnhancedQName expected, @NonNull String metapath) { IStringItem result = IMetapathExpression.compile(metapath, dynamicContext.getStaticContext()) .evaluateAs( - MockedDocumentGenerator.generateDocumentNodeItem(getContext()), + MockedDocumentGenerator.generateDocumentNodeItem(), IMetapathExpression.ResultType.ITEM, dynamicContext); assertNotNull(result); diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnNameTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnNameTest.java index 5b9a376d9..0937e6a89 100644 --- a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnNameTest.java +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnNameTest.java @@ -65,7 +65,7 @@ void test(@Nullable IEnhancedQName expected, @NonNull String metapath) { IStringItem result = IMetapathExpression.compile(metapath, dynamicContext.getStaticContext()) .evaluateAs( - MockedDocumentGenerator.generateDocumentNodeItem(getContext()), + MockedDocumentGenerator.generateDocumentNodeItem(), IMetapathExpression.ResultType.ITEM, dynamicContext); assertNotNull(result); diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnNamespaceUriTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnNamespaceUriTest.java index 632738974..23c3b2b52 100644 --- a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnNamespaceUriTest.java +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnNamespaceUriTest.java @@ -66,7 +66,7 @@ void test(@Nullable IEnhancedQName expected, @NonNull String metapath) { IStringItem result = IMetapathExpression.compile(metapath, dynamicContext.getStaticContext()) .evaluateAs( - MockedDocumentGenerator.generateDocumentNodeItem(getContext()), + MockedDocumentGenerator.generateDocumentNodeItem(), IMetapathExpression.ResultType.ITEM, dynamicContext); assertNotNull(result); diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnOutermostTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnOutermostTest.java index e54963f98..72e8791c9 100644 --- a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnOutermostTest.java +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnOutermostTest.java @@ -59,7 +59,7 @@ private static Stream provideValues() { // NOPMD - false positive @MethodSource("provideValues") void test(@NonNull String expectedValueMetapath, @NonNull String actualValuesMetapath) { DynamicContext dynamicContext = newDynamicContext(); - INodeItem node = MockedDocumentGenerator.generateDocumentNodeItem(getContext()); + INodeItem node = MockedDocumentGenerator.generateDocumentNodeItem(); ISequence expected = IMetapathExpression.compile(expectedValueMetapath, dynamicContext.getStaticContext()) diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnRootTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnRootTest.java index e8d4c330f..fabe74d4e 100644 --- a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnRootTest.java +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnRootTest.java @@ -55,7 +55,7 @@ private static Stream provideValues() { // NOPMD - false positive void test(@NonNull String metapath) { DynamicContext dynamicContext = newDynamicContext(); - INodeItem root = MockedDocumentGenerator.generateDocumentNodeItem(getContext()); + INodeItem root = MockedDocumentGenerator.generateDocumentNodeItem(); INodeItem result = IMetapathExpression.compile(metapath, dynamicContext.getStaticContext()) .evaluateAs(root, IMetapathExpression.ResultType.ITEM, dynamicContext); INodeItem rootResult diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/impl/MockedDocumentGenerator.java b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/impl/MockedDocumentGenerator.java index 3b1b39aa4..eddbf2821 100644 --- a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/impl/MockedDocumentGenerator.java +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/impl/MockedDocumentGenerator.java @@ -14,17 +14,16 @@ import gov.nist.secauto.metaschema.core.model.IAssemblyInstance; import gov.nist.secauto.metaschema.core.model.IFieldInstance; import gov.nist.secauto.metaschema.core.model.IFlagInstance; -import gov.nist.secauto.metaschema.core.model.IResourceLocation; import gov.nist.secauto.metaschema.core.qname.IEnhancedQName; import gov.nist.secauto.metaschema.core.testing.MockedModelTestSupport; -import org.jmock.Mockery; - import java.net.URI; import edu.umd.cs.findbugs.annotations.NonNull; public class MockedDocumentGenerator { + @NonNull + public static final URI BASE_URI = URI.create("https://example.com/resource"); @NonNull public static final String NS = "http://example.com/ns"; @NonNull @@ -38,9 +37,8 @@ public class MockedDocumentGenerator { @NonNull public static final IEnhancedQName FIELD_FLAG_QNAME = IEnhancedQName.of("field-flag"); - public static IDMDocumentNodeItem generateDocumentNodeItem(@NonNull Mockery context) { - MockedModelTestSupport mocking = new MockedModelTestSupport(context); - IResourceLocation resourceLocation = mocking.mock(IResourceLocation.class); + public static IDMDocumentNodeItem generateDocumentNodeItem() { + MockedModelTestSupport mocking = new MockedModelTestSupport(); IAssemblyDefinition rootDefinition = mocking.assembly().qname(ROOT_QNAME).rootQName(ROOT_QNAME).toDefinition(); IAssemblyInstance assemblyInstance = mocking.assembly().qname(ASSEMBLY_QNAME).toInstance(rootDefinition); @@ -49,16 +47,13 @@ public static IDMDocumentNodeItem generateDocumentNodeItem(@NonNull Mockery cont IFlagInstance fieldFlag = mocking.flag().qname(FIELD_FLAG_QNAME).toInstance(fieldInstance.getDefinition()); IDMDocumentNodeItem document = IDMDocumentNodeItem.newInstance( - URI.create("https://example.com/resource"), - resourceLocation, - rootDefinition, - resourceLocation); + BASE_URI, + rootDefinition); IDMRootAssemblyNodeItem root = document.getRootAssemblyNodeItem(); - IDMAssemblyNodeItem assembly = root.newAssembly(assemblyInstance, resourceLocation); - assembly.newFlag(assemblyFlag, resourceLocation, IStringItem.valueOf("assembly-flag")); - IDMFieldNodeItem field = root.newField(fieldInstance, resourceLocation, IStringItem.valueOf("field")); - field.newFlag(fieldFlag, resourceLocation, IStringItem.valueOf("field-flag")); - + IDMAssemblyNodeItem assembly = root.newAssembly(assemblyInstance); + assembly.newFlag(assemblyFlag, IStringItem.valueOf("assembly-flag")); + IDMFieldNodeItem field = root.newField(fieldInstance, IStringItem.valueOf("field")); + field.newFlag(fieldFlag, IStringItem.valueOf("field-flag")); return document; } diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/item/node/DefaultNodeItemFactoryTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/item/node/DefaultNodeItemFactoryTest.java index bd81cfab3..f22867577 100644 --- a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/item/node/DefaultNodeItemFactoryTest.java +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/item/node/DefaultNodeItemFactoryTest.java @@ -7,18 +7,18 @@ import static org.hamcrest.Matchers.equalTo; import static org.junit.jupiter.api.Assertions.assertAll; +import gov.nist.secauto.metaschema.core.mdm.IDMAssemblyNodeItem; +import gov.nist.secauto.metaschema.core.metapath.StaticContext; +import gov.nist.secauto.metaschema.core.metapath.item.atomic.IStringItem; import gov.nist.secauto.metaschema.core.model.IAssemblyDefinition; -import gov.nist.secauto.metaschema.core.model.IFieldInstance; import gov.nist.secauto.metaschema.core.qname.IEnhancedQName; import gov.nist.secauto.metaschema.core.testing.MockedModelTestSupport; import gov.nist.secauto.metaschema.core.util.ObjectUtils; import org.hamcrest.FeatureMatcher; import org.hamcrest.Matcher; -import org.jmock.Expectations; import org.junit.jupiter.api.Test; -import java.net.URI; import java.util.Collection; import java.util.List; import java.util.function.Function; @@ -29,78 +29,28 @@ class DefaultNodeItemFactoryTest extends MockedModelTestSupport { @NonNull - private static final URI NS_URI = ObjectUtils.notNull(URI.create("http://example.com/ns")); - @NonNull - private static final String NS = ObjectUtils.notNull(NS_URI.toASCIIString()); - - @Test - void testGenerateFlags() { - DefaultNodeItemFactory nodeFactory = DefaultNodeItemFactory.instance(); - - IAssemblyDefinition parent = assembly() - .namespace(NS_URI) - .name("assembly1") - .toDefinition(); - - IFieldInstance fieldInstance = field() - .namespace(NS_URI) - .name("field1") - .flags(List.of( - flag().namespace(NS_URI).name("flag1"))) - .toInstance(parent); - - Object fieldValue = "test value"; - - // setup the value calls - getContext().checking(new Expectations() { - { // NOPMD - intentional - allowing(fieldInstance.getDefinition().getFlagInstanceByName(IEnhancedQName.of(NS, "flag1").getIndexPosition())) - .getValue(fieldValue); - will(returnValue("flag1 value")); - } - }); - - IAssemblyNodeItem parentItem = INodeItemFactory.instance().newAssemblyNodeItem(parent); - IFieldNodeItem field = new FieldInstanceNodeItemImpl(fieldInstance, parentItem, 2, fieldValue, nodeFactory); - - Collection flagItems = field.getFlags(); - assertThat(flagItems, containsInAnyOrder( - allOf( - match("name", IFlagNodeItem::getQName, equalTo(IEnhancedQName.of(NS, "flag1"))), - match("value", IFlagNodeItem::getValue, equalTo("flag1 value"))))); // NOPMD - } + private static final String NS = ObjectUtils.notNull("http://example.com/ns"); @Test void testGenerateModelItems() { IAssemblyDefinition assembly = assembly() - .namespace(NS_URI) + .namespace(NS) .name("assembly1") .flags(List.of( - flag().namespace(NS_URI).name("flag1"))) + flag().namespace(NS).name("flag1"))) .modelInstances(List.of( - field().namespace(NS_URI).name("field1"))) + field().namespace(NS).name("field1"))) .toDefinition(); - Object assemblyValue = "assembly value"; - Object flagValue = "flag1 value"; - Object fieldValue = "field1 value"; - // Setup the value calls - getContext().checking(new Expectations() { - { // NOPMD - intentional - allowing(assembly.getFlagInstanceByName(IEnhancedQName.of(NS, "flag1").getIndexPosition())) - .getValue(assemblyValue); - will(returnValue(flagValue)); - allowing(assembly.getNamedModelInstanceByName(IEnhancedQName.of(NS, "field1").getIndexPosition())) - .getValue(assemblyValue); - will(returnValue(fieldValue)); - allowing(assembly.getNamedModelInstanceByName(IEnhancedQName.of(NS, "field1").getIndexPosition())) - .getItemValues(fieldValue); - will(returnValue(List.of(fieldValue))); - } - }); - - IAssemblyNodeItem parentItem = INodeItemFactory.instance().newAssemblyNodeItem(assembly, null, assemblyValue); + StaticContext staticContext = StaticContext.instance(); + IDMAssemblyNodeItem parentItem = IDMAssemblyNodeItem.newInstance(assembly, staticContext); + assembly.getFlagInstances() + .forEach(flag -> parentItem.newFlag(flag, IStringItem.valueOf(flag.getName() + " value"))); + assembly.getFieldInstances() + .forEach(field -> { + parentItem.newField(field, IStringItem.valueOf(field.getName() + " value")); + }); Collection flagItems = parentItem.getFlags(); Collection> modelItems = parentItem.modelItems() @@ -109,13 +59,12 @@ void testGenerateModelItems() { () -> assertThat(flagItems, containsInAnyOrder( allOf( match("name", IFlagNodeItem::getQName, equalTo(IEnhancedQName.of(NS, "flag1"))), - match("value", IFlagNodeItem::getValue, equalTo("flag1 value"))))), + match("value", node -> node.toAtomicItem().asString(), equalTo("flag1 value"))))), () -> assertThat(modelItems, containsInAnyOrder( allOf( match("name", IModelNodeItem::getQName, equalTo(IEnhancedQName.of(NS, "field1"))), - match("value", IModelNodeItem::getValue, - equalTo("field1 value")))))); + match("value", node -> node.toAtomicItem().asString(), equalTo("field1 value")))))); } private static FeatureMatcher match( diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/item/node/MockNodeItemFactory.java b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/item/node/MockNodeItemFactory.java index aa6352f9a..15b2c3b05 100644 --- a/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/item/node/MockNodeItemFactory.java +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/item/node/MockNodeItemFactory.java @@ -3,26 +3,22 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.withSettings; import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyAtomicItem; import gov.nist.secauto.metaschema.core.model.IAssemblyDefinition; import gov.nist.secauto.metaschema.core.model.IFieldDefinition; import gov.nist.secauto.metaschema.core.model.IFlagDefinition; import gov.nist.secauto.metaschema.core.qname.IEnhancedQName; +import gov.nist.secauto.metaschema.core.testing.mocking.AbstractMockitoFactory; import gov.nist.secauto.metaschema.core.util.CollectionUtil; import gov.nist.secauto.metaschema.core.util.ObjectUtils; -import org.mockito.Answers; -import org.mockito.Mockito; - import java.net.URI; import java.util.Collections; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; import edu.umd.cs.findbugs.annotations.NonNull; @@ -31,20 +27,8 @@ // TODO: Integrate with classes in gov.nist.secauto.metaschema.core.testing @SuppressWarnings("checkstyle:MissingJavadocMethodCheck") @SuppressFBWarnings("RV_RETURN_VALUE_IGNORED_NO_SIDE_EFFECT") -public class MockNodeItemFactory { - @SuppressWarnings("null") - @NonNull - protected T newMock(@NonNull Class clazz, @NonNull String name) { - String mockName = new StringBuilder() - .append(clazz.getSimpleName()) - .append('-') - .append(name) - .append('-') - .append(UUID.randomUUID().toString()) - .toString(); - return Mockito.mock(clazz, withSettings().name(mockName).defaultAnswer(Answers.CALLS_REAL_METHODS)); - } - +public class MockNodeItemFactory + extends AbstractMockitoFactory { @NonNull public IDocumentNodeItem document( URI documentURI, @@ -52,9 +36,9 @@ public IDocumentNodeItem document( List flags, List> modelItems) { String qname = ObjectUtils.requireNonNull(rootName.toString()); - IDocumentNodeItem document = newMock(IDocumentNodeItem.class, qname); - IRootAssemblyNodeItem root = newMock(IRootAssemblyNodeItem.class, qname); - IAssemblyDefinition definition = newMock(IAssemblyDefinition.class, qname); + IDocumentNodeItem document = mock(IDocumentNodeItem.class, qname); + IRootAssemblyNodeItem root = mock(IRootAssemblyNodeItem.class, qname); + IAssemblyDefinition definition = mock(IAssemblyDefinition.class, qname); // doAnswer(invocation -> Stream.of(root)).when(document).modelItems(); doReturn(root).when(document).getRootAssemblyNodeItem(); @@ -136,8 +120,8 @@ protected void handleChildren( @NonNull public IFlagNodeItem flag(@NonNull IEnhancedQName name, @NonNull IAnyAtomicItem value) { - IFlagNodeItem flag = newMock(IFlagNodeItem.class, ObjectUtils.notNull(name.toString())); - IFlagDefinition definition = newMock(IFlagDefinition.class, ObjectUtils.notNull(name.toString())); + IFlagNodeItem flag = mock(IFlagNodeItem.class, ObjectUtils.notNull(name.toString())); + IFlagDefinition definition = mock(IFlagDefinition.class, ObjectUtils.notNull(name.toString())); doReturn(name).when(flag).getQName(); doReturn(true).when(flag).hasValue(); @@ -163,8 +147,8 @@ public IFieldNodeItem field( @NonNull IEnhancedQName name, @NonNull IAnyAtomicItem value, List flags) { - IFieldNodeItem field = newMock(IFieldNodeItem.class, ObjectUtils.notNull(name.toString())); - IFieldDefinition definition = newMock(IFieldDefinition.class, ObjectUtils.notNull(name.toString())); + IFieldNodeItem field = mock(IFieldNodeItem.class, ObjectUtils.notNull(name.toString())); + IFieldDefinition definition = mock(IFieldDefinition.class, ObjectUtils.notNull(name.toString())); doReturn(name).when(field).getQName(); doReturn(true).when(field).hasValue(); @@ -184,8 +168,8 @@ public IAssemblyNodeItem assembly( @NonNull IEnhancedQName name, List flags, List> modelItems) { - IAssemblyNodeItem assembly = newMock(IAssemblyNodeItem.class, ObjectUtils.notNull(name.toString())); - IAssemblyDefinition definition = newMock(IAssemblyDefinition.class, ObjectUtils.notNull(name.toString())); + IAssemblyNodeItem assembly = mock(IAssemblyNodeItem.class, ObjectUtils.notNull(name.toString())); + IAssemblyDefinition definition = mock(IAssemblyDefinition.class, ObjectUtils.notNull(name.toString())); doReturn(name).when(assembly).getQName(); doReturn(false).when(assembly).hasValue(); diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/model/constraint/impl/AbstractConfigurableMessageConstraintTest.java b/core/src/test/java/gov/nist/secauto/metaschema/core/model/constraint/impl/AbstractConfigurableMessageConstraintTest.java new file mode 100644 index 000000000..ca6e91390 --- /dev/null +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/model/constraint/impl/AbstractConfigurableMessageConstraintTest.java @@ -0,0 +1,138 @@ +/* + * SPDX-FileCopyrightText: none + * SPDX-License-Identifier: CC0-1.0 + */ + +package gov.nist.secauto.metaschema.core.model.constraint.impl; + +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import gov.nist.secauto.metaschema.core.metapath.DynamicContext; +import gov.nist.secauto.metaschema.core.metapath.ExpressionTestBase; +import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression; +import gov.nist.secauto.metaschema.core.metapath.StaticContext; +import gov.nist.secauto.metaschema.core.metapath.function.library.impl.MockedDocumentGenerator; +import gov.nist.secauto.metaschema.core.metapath.item.node.IDocumentNodeItem; +import gov.nist.secauto.metaschema.core.model.ISource; +import gov.nist.secauto.metaschema.core.model.constraint.DefaultConstraintValidator; +import gov.nist.secauto.metaschema.core.model.constraint.FindingCollectingConstraintValidationHandler; +import gov.nist.secauto.metaschema.core.model.constraint.IExpectConstraint; + +import org.junit.jupiter.api.Test; + +import java.net.URI; + +class AbstractConfigurableMessageConstraintTest + extends ExpressionTestBase { + + @Test + void testDifferentNS() { + StaticContext constraintContext = StaticContext.builder() + .defaultModelNamespace(NS) + .baseUri(URI.create("https://example.com/other")) + .build(); + + IExpectConstraint expect = IExpectConstraint.builder() + .target(IMetapathExpression.compile("assembly", constraintContext)) + .test(IMetapathExpression.compile("ancestor::root", constraintContext)) + .source(ISource.externalSource(constraintContext, false)) + .build(); + + IDocumentNodeItem document = MockedDocumentGenerator.generateDocumentNodeItem(); + document.getRootAssemblyNodeItem().getDefinition().addConstraint(expect); + + FindingCollectingConstraintValidationHandler handler = new FindingCollectingConstraintValidationHandler(); + DefaultConstraintValidator validator = new DefaultConstraintValidator(handler); + validator.validate( + document, + new DynamicContext(document.getStaticContext())); + + assertAll( + () -> assertTrue(handler.isPassing()), + () -> assertEquals(0, handler.getFindings().size())); + } + + @Test + void testWildCard() { + StaticContext constraintContext = StaticContext.builder() + .defaultModelNamespace(NS) + .baseUri(URI.create("https://example.com/other")) + .build(); + + IExpectConstraint expect = IExpectConstraint.builder() + .target(IMetapathExpression.compile("assembly", constraintContext)) + .test(IMetapathExpression.compile("ancestor::*:root", constraintContext)) + .source(ISource.externalSource(constraintContext, false)) + .build(); + + IDocumentNodeItem document = MockedDocumentGenerator.generateDocumentNodeItem(); + document.getRootAssemblyNodeItem().getDefinition().addConstraint(expect); + + FindingCollectingConstraintValidationHandler handler = new FindingCollectingConstraintValidationHandler(); + DefaultConstraintValidator validator = new DefaultConstraintValidator(handler); + validator.validate( + document, + new DynamicContext(document.getStaticContext())); + + assertAll( + () -> assertTrue(handler.isPassing()), + () -> assertEquals(0, handler.getFindings().size())); + } + + @Test + void testPrefix() { + StaticContext constraintContext = StaticContext.builder() + .defaultModelNamespace(NS) + .baseUri(URI.create("https://example.com/other")) + .namespace("ns", MockedDocumentGenerator.NS) + .build(); + + IExpectConstraint expect = IExpectConstraint.builder() + .target(IMetapathExpression.compile("ns:assembly", constraintContext)) + .test(IMetapathExpression.compile("ancestor::ns:root", constraintContext)) + .source(ISource.externalSource(constraintContext, false)) + .build(); + + IDocumentNodeItem document = MockedDocumentGenerator.generateDocumentNodeItem(); + document.getRootAssemblyNodeItem().getDefinition().addConstraint(expect); + + FindingCollectingConstraintValidationHandler handler = new FindingCollectingConstraintValidationHandler(); + DefaultConstraintValidator validator = new DefaultConstraintValidator(handler); + validator.validate( + document, + new DynamicContext(document.getStaticContext())); + + assertAll( + () -> assertTrue(handler.isPassing()), + () -> assertEquals(0, handler.getFindings().size())); + } + + @Test + void testQualifiedName() { + StaticContext constraintContext = StaticContext.builder() + .defaultModelNamespace(NS) + .baseUri(URI.create("https://example.com/other")) + .build(); + + IExpectConstraint expect = IExpectConstraint.builder() + .target(IMetapathExpression.compile("Q{" + MockedDocumentGenerator.NS + "}assembly", constraintContext)) + .test(IMetapathExpression.compile("ancestor::Q{" + MockedDocumentGenerator.NS + "}root", constraintContext)) + .source(ISource.externalSource(constraintContext, false)) + .build(); + + IDocumentNodeItem document = MockedDocumentGenerator.generateDocumentNodeItem(); + document.getRootAssemblyNodeItem().getDefinition().addConstraint(expect); + + FindingCollectingConstraintValidationHandler handler = new FindingCollectingConstraintValidationHandler(); + DefaultConstraintValidator validator = new DefaultConstraintValidator(handler); + validator.validate( + document, + new DynamicContext(document.getStaticContext())); + + assertAll( + () -> assertTrue(handler.isPassing()), + () -> assertEquals(0, handler.getFindings().size())); + } +} diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/testing/AbstractModelBuilder.java b/core/src/test/java/gov/nist/secauto/metaschema/core/testing/AbstractModelBuilder.java index 67c2a47cf..996c9b05a 100644 --- a/core/src/test/java/gov/nist/secauto/metaschema/core/testing/AbstractModelBuilder.java +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/testing/AbstractModelBuilder.java @@ -5,19 +5,20 @@ package gov.nist.secauto.metaschema.core.testing; +import static org.mockito.Mockito.doReturn; + import gov.nist.secauto.metaschema.core.model.IAttributable; import gov.nist.secauto.metaschema.core.model.IDefinition; import gov.nist.secauto.metaschema.core.model.IModelDefinition; import gov.nist.secauto.metaschema.core.model.IModelElement; import gov.nist.secauto.metaschema.core.model.INamedInstance; import gov.nist.secauto.metaschema.core.model.INamedModelElement; +import gov.nist.secauto.metaschema.core.model.ISource; import gov.nist.secauto.metaschema.core.qname.IEnhancedQName; +import gov.nist.secauto.metaschema.core.testing.mocking.AbstractMockitoFactory; import gov.nist.secauto.metaschema.core.util.CollectionUtil; import gov.nist.secauto.metaschema.core.util.ObjectUtils; -import org.jmock.Expectations; -import org.jmock.Mockery; - import java.net.URI; import edu.umd.cs.findbugs.annotations.NonNull; @@ -29,19 +30,17 @@ * the Java type of this builder */ public abstract class AbstractModelBuilder> - extends MockFactory { + extends AbstractMockitoFactory { private String namespace = ""; private String name; + protected ISource source; /** - * Construct a new builder using the provided mocking context. - * - * @param ctx - * the mocking context + * Construct a new builder. */ - protected AbstractModelBuilder(@NonNull Mockery ctx) { - super(ctx); + protected AbstractModelBuilder() { + // allow extending classes to construct } /** @@ -131,12 +130,17 @@ protected void applyDefinition(@NonNull IDefinition definition) { applyModelElement(definition); applyNamed(definition); applyAttributable(definition); - getContext().checking(new Expectations() { - { - allowing(definition).getDefinitionQName(); - will(returnValue(IEnhancedQName.of(ObjectUtils.notNull(namespace), ObjectUtils.notNull(name)))); - } - }); + + IEnhancedQName qname = IEnhancedQName.of(ObjectUtils.notNull(namespace), ObjectUtils.notNull(name)); + + doReturn(qname).when(definition).getDefinitionQName(); + doReturn(null).when(definition).getRemarks(); + doReturn(CollectionUtil.emptyMap()).when(definition).getProperties(); + doReturn(null).when(definition).getInlineInstance(); + + // doReturn().when(definition).getConstraintSupport(); + // doReturn().when(definition).getContainingModule(); + // doReturn().when(definition).getModelType(); } /** @@ -159,18 +163,11 @@ protected void applyNamedInstance( applyModelElement(instance); applyNamed(instance); applyAttributable(instance); - getContext().checking(new Expectations() { - { - allowing(instance).getQName(); - will(returnValue(IEnhancedQName.of(ObjectUtils.notNull(namespace), ObjectUtils.notNull(name)))); - allowing(instance).getDefinition(); - will(returnValue(definition)); - allowing(instance).getContainingDefinition(); - will(returnValue(parent)); - allowing(instance).getParentContainer(); - will(returnValue(parent)); - } - }); + + doReturn(name).when(instance).getName(); + doReturn(definition).when(instance).getDefinition(); + doReturn(parent).when(instance).getContainingDefinition(); + doReturn(parent).when(instance).getParentContainer(); } /** @@ -181,22 +178,12 @@ protected void applyNamedInstance( * the named model element to apply mocking expectations for */ protected void applyNamed(@NonNull INamedModelElement element) { - getContext().checking(new Expectations() { - { - allowing(element).getName(); - will(returnValue(name)); - allowing(element).getUseName(); - will(returnValue(null)); - allowing(element).getQName(); - will(returnValue(IEnhancedQName.of(ObjectUtils.notNull(namespace), ObjectUtils.notNull(name)))); - allowing(element).getEffectiveName(); - will(returnValue(name)); - allowing(element).getFormalName(); - will(returnValue(null)); - allowing(element).getDescription(); - will(returnValue(null)); - } - }); + IEnhancedQName qname = IEnhancedQName.of(ObjectUtils.notNull(namespace), ObjectUtils.notNull(name)); + + doReturn(qname).when(element).getQName(); + doReturn(name).when(element).getName(); + doReturn(null).when(element).getFormalName(); + doReturn(null).when(element).getDescription(); } /** @@ -207,12 +194,7 @@ protected void applyNamed(@NonNull INamedModelElement element) { * the element to apply mocking expectations for */ protected void applyAttributable(@NonNull IAttributable element) { - getContext().checking(new Expectations() { - { - allowing(element).getProperties(); - will(returnValue(CollectionUtil.emptyMap())); - } - }); + doReturn(CollectionUtil.emptyMap()).when(element).getProperties(); } /** @@ -222,11 +204,6 @@ protected void applyAttributable(@NonNull IAttributable element) { * the model element to apply mocking expectations for */ protected void applyModelElement(@NonNull IModelElement element) { - getContext().checking(new Expectations() { - { - allowing(element).getRemarks(); - will(returnValue(null)); - } - }); + doReturn(null).when(element).getRemarks(); } } diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/testing/AssemblyBuilder.java b/core/src/test/java/gov/nist/secauto/metaschema/core/testing/AssemblyBuilder.java index 3f8da001d..4007a13b0 100644 --- a/core/src/test/java/gov/nist/secauto/metaschema/core/testing/AssemblyBuilder.java +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/testing/AssemblyBuilder.java @@ -5,22 +5,28 @@ package gov.nist.secauto.metaschema.core.testing; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; + import gov.nist.secauto.metaschema.core.model.IAssemblyDefinition; +import gov.nist.secauto.metaschema.core.model.IAssemblyInstance; import gov.nist.secauto.metaschema.core.model.IAssemblyInstanceAbsolute; +import gov.nist.secauto.metaschema.core.model.IFieldInstance; import gov.nist.secauto.metaschema.core.model.IFlagInstance; +import gov.nist.secauto.metaschema.core.model.INamedModelElement; import gov.nist.secauto.metaschema.core.model.INamedModelInstanceAbsolute; +import gov.nist.secauto.metaschema.core.model.ModelType; +import gov.nist.secauto.metaschema.core.model.constraint.AssemblyConstraintSet; import gov.nist.secauto.metaschema.core.qname.IEnhancedQName; import gov.nist.secauto.metaschema.core.util.CollectionUtil; import gov.nist.secauto.metaschema.core.util.ObjectUtils; -import org.jmock.Expectations; -import org.jmock.Mockery; - import java.net.URI; import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; +import java.util.stream.Stream; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; @@ -34,20 +40,18 @@ public final class AssemblyBuilder private List flags; private List modelInstances; - private AssemblyBuilder(@NonNull Mockery ctx) { - super(ctx); + private AssemblyBuilder() { + // prevent direct instantiation } /** * Create a new builder using the provided mocking context. * - * @param ctx - * the mocking context * @return the new builder */ @NonNull - public static AssemblyBuilder builder(@NonNull Mockery ctx) { - return new AssemblyBuilder(ctx).reset(); + public static AssemblyBuilder builder() { + return new AssemblyBuilder().reset(); } @Override @@ -186,28 +190,50 @@ public IAssemblyDefinition toDefinition() { INamedModelInstanceAbsolute::getQName, Function.identity())); - getContext().checking(new Expectations() { - { - if (rootName != null) { - allowing(retval).getRootQName(); - will(returnValue(IEnhancedQName.of(ObjectUtils.notNull(rootNamespace), ObjectUtils.notNull(rootName)))); - } - - allowing(retval).getFlagInstances(); - will(returnValue(flags.values())); - flags.forEach((key, value) -> { - allowing(retval).getFlagInstanceByName(with(key.getIndexPosition())); - will(returnValue(value)); - }); - allowing(retval).getModelInstances(); - will(returnValue(modelInstances.values())); - modelInstances.forEach((key, value) -> { - allowing(retval).getNamedModelInstanceByName(with(key.getIndexPosition())); - will(returnValue(value)); - }); - } + if (rootName != null) { + doReturn(ModelType.ASSEMBLY).when(retval).getModelType(); + + IEnhancedQName rootQName = IEnhancedQName.of(ObjectUtils.notNull(rootNamespace), ObjectUtils.notNull(rootName)); + doReturn(rootQName).when(retval).getRootQName(); + } + + doReturn(new AssemblyConstraintSet(source)).when(retval).getConstraintSupport(); + + doReturn(flags.values()).when(retval).getFlagInstances(); + flags.entrySet().forEach(entry -> { + assert entry != null; + doReturn(entry.getValue()).when(retval).getFlagInstanceByName(eq(entry.getKey().getIndexPosition())); }); + doReturn(modelInstances.values()).when(retval).getModelInstances(); + doReturn(CollectionUtil.emptyMap()).when(retval).getChoiceGroupInstances(); + doReturn(CollectionUtil.emptyList()).when(retval).getChoiceInstances(); + modelInstances.forEach((key, value) -> { + doReturn(value).when(retval).getNamedModelInstanceByName(eq(key.getIndexPosition())); + + if (value instanceof IAssemblyInstance) { + doReturn(value).when(retval).getAssemblyInstanceByName(eq(key.getIndexPosition())); + } else if (value instanceof IFieldInstance) { + doReturn(value).when(retval).getFieldInstanceByName(eq(key.getIndexPosition())); + } + }); + doReturn( + modelInstances.values().stream() + .flatMap(value -> value instanceof IAssemblyInstance ? Stream.of(value) : null) + .collect(Collectors.toList())) + .when(retval).getAssemblyInstances(); + doReturn( + modelInstances.values().stream() + .flatMap(value -> value instanceof IFieldInstance ? Stream.of(value) : null) + .collect(Collectors.toList())) + .when(retval).getFieldInstances(); return retval; } + + @Override + protected void applyNamed(INamedModelElement element) { + super.applyNamed(element); + doReturn(ModelType.ASSEMBLY).when(element).getModelType(); + } + } diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/testing/FieldBuilder.java b/core/src/test/java/gov/nist/secauto/metaschema/core/testing/FieldBuilder.java index 25adead9f..759df2a84 100644 --- a/core/src/test/java/gov/nist/secauto/metaschema/core/testing/FieldBuilder.java +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/testing/FieldBuilder.java @@ -5,18 +5,21 @@ package gov.nist.secauto.metaschema.core.testing; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; + import gov.nist.secauto.metaschema.core.datatype.IDataTypeAdapter; import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider; import gov.nist.secauto.metaschema.core.model.IAssemblyDefinition; import gov.nist.secauto.metaschema.core.model.IFieldDefinition; import gov.nist.secauto.metaschema.core.model.IFieldInstanceAbsolute; import gov.nist.secauto.metaschema.core.model.IFlagInstance; +import gov.nist.secauto.metaschema.core.model.INamedModelElement; +import gov.nist.secauto.metaschema.core.model.ModelType; +import gov.nist.secauto.metaschema.core.model.constraint.ValueConstraintSet; import gov.nist.secauto.metaschema.core.qname.IEnhancedQName; import gov.nist.secauto.metaschema.core.util.CollectionUtil; -import org.jmock.Expectations; -import org.jmock.Mockery; - import java.util.List; import java.util.Map; import java.util.function.Function; @@ -33,20 +36,18 @@ public final class FieldBuilder private Object defaultValue = null; private List flags; - private FieldBuilder(@NonNull Mockery ctx) { - super(ctx); + private FieldBuilder() { + // prevent direct instantiation } /** * Create a new builder using the provided mocking context. * - * @param ctx - * the mocking context * @return the new builder */ @NonNull - public static FieldBuilder builder(@NonNull Mockery ctx) { - return new FieldBuilder(ctx).reset(); + public static FieldBuilder builder() { + return new FieldBuilder().reset(); } @Override @@ -148,21 +149,22 @@ public IFieldDefinition toDefinition() { IFlagInstance::getQName, Function.identity())); - getContext().checking(new Expectations() { - { - allowing(retval).getJavaTypeAdapter(); - will(returnValue(dataTypeAdapter)); - allowing(retval).getDefaultValue(); - will(returnValue(defaultValue)); - allowing(retval).getFlagInstances(); - will(returnValue(flags.values())); - flags.forEach((key, value) -> { - allowing(retval).getFlagInstanceByName(with(key.getIndexPosition())); - will(returnValue(value)); - }); - } + doReturn(new ValueConstraintSet(source)).when(retval).getConstraintSupport(); + doReturn(dataTypeAdapter).when(retval).getJavaTypeAdapter(); + doReturn(defaultValue).when(retval).getDefaultValue(); + + doReturn(flags.values()).when(retval).getFlagInstances(); + flags.entrySet().forEach(entry -> { + assert entry != null; + doReturn(entry.getValue()).when(retval).getFlagInstanceByName(eq(entry.getKey().getIndexPosition())); }); return retval; } + + @Override + protected void applyNamed(INamedModelElement element) { + super.applyNamed(element); + doReturn(ModelType.FIELD).when(element).getModelType(); + } } diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/testing/FlagBuilder.java b/core/src/test/java/gov/nist/secauto/metaschema/core/testing/FlagBuilder.java index 32c902b77..9ca30c645 100644 --- a/core/src/test/java/gov/nist/secauto/metaschema/core/testing/FlagBuilder.java +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/testing/FlagBuilder.java @@ -5,14 +5,17 @@ package gov.nist.secauto.metaschema.core.testing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + import gov.nist.secauto.metaschema.core.datatype.IDataTypeAdapter; import gov.nist.secauto.metaschema.core.datatype.adapter.MetaschemaDataTypeProvider; import gov.nist.secauto.metaschema.core.model.IFlagDefinition; import gov.nist.secauto.metaschema.core.model.IFlagInstance; import gov.nist.secauto.metaschema.core.model.IModelDefinition; - -import org.jmock.Expectations; -import org.jmock.Mockery; +import gov.nist.secauto.metaschema.core.model.INamedModelElement; +import gov.nist.secauto.metaschema.core.model.ModelType; +import gov.nist.secauto.metaschema.core.model.constraint.ValueConstraintSet; import edu.umd.cs.findbugs.annotations.NonNull; @@ -26,20 +29,18 @@ public final class FlagBuilder private Object defaultValue = null; private boolean required; - private FlagBuilder(@NonNull Mockery ctx) { - super(ctx); + private FlagBuilder() { + // prevent direct instantiation } /** * Create a new builder using the provided mocking context. * - * @param ctx - * the mocking context * @return the new builder */ @NonNull - public static FlagBuilder builder(@NonNull Mockery ctx) { - return new FlagBuilder(ctx).reset(); + public static FlagBuilder builder() { + return new FlagBuilder().reset(); } @Override @@ -120,13 +121,7 @@ public IFlagInstance toInstance( applyNamedInstance(retval, definition, parent); - getContext().checking(new Expectations() { - { - allowing(retval).isRequired(); - will(returnValue(required)); - } - }); - + doReturn(required).when(retval).isRequired(); return retval; } @@ -142,14 +137,16 @@ public IFlagDefinition toDefinition() { IFlagDefinition retval = mock(IFlagDefinition.class); applyDefinition(retval); - getContext().checking(new Expectations() { - { - allowing(retval).getJavaTypeAdapter(); - will(returnValue(dataTypeAdapter)); - allowing(retval).getDefaultValue(); - will(returnValue(defaultValue)); - } - }); + doReturn(new ValueConstraintSet(source)).when(retval).getConstraintSupport(); + doReturn(dataTypeAdapter).when(retval).getJavaTypeAdapter(); + doReturn(defaultValue).when(retval).getDefaultValue(); + return retval; } + + @Override + protected void applyNamed(INamedModelElement element) { + super.applyNamed(element); + doReturn(ModelType.FLAG).when(element).getModelType(); + } } diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/testing/IModuleMockFactory.java b/core/src/test/java/gov/nist/secauto/metaschema/core/testing/IModuleMockFactory.java index fc6a9e624..dd7f8f6d1 100644 --- a/core/src/test/java/gov/nist/secauto/metaschema/core/testing/IModuleMockFactory.java +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/testing/IModuleMockFactory.java @@ -5,15 +5,11 @@ package gov.nist.secauto.metaschema.core.testing; -import org.jmock.Mockery; +import gov.nist.secauto.metaschema.core.testing.mocking.IMockFactory; import edu.umd.cs.findbugs.annotations.NonNull; public interface IModuleMockFactory extends IMockFactory { - @Override - @NonNull - Mockery getContext(); - /** * Get a new flag builder. * @@ -21,7 +17,7 @@ public interface IModuleMockFactory extends IMockFactory { */ @NonNull default FlagBuilder flag() { - return FlagBuilder.builder(getContext()); + return FlagBuilder.builder(); } /** @@ -31,7 +27,7 @@ default FlagBuilder flag() { */ @NonNull default FieldBuilder field() { - return FieldBuilder.builder(getContext()); + return FieldBuilder.builder(); } /** @@ -41,6 +37,6 @@ default FieldBuilder field() { */ @NonNull default AssemblyBuilder assembly() { - return AssemblyBuilder.builder(getContext()); + return AssemblyBuilder.builder(); } } diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/testing/MockedModelTestSupport.java b/core/src/test/java/gov/nist/secauto/metaschema/core/testing/MockedModelTestSupport.java index 96d17b74b..cd5bf5229 100644 --- a/core/src/test/java/gov/nist/secauto/metaschema/core/testing/MockedModelTestSupport.java +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/testing/MockedModelTestSupport.java @@ -5,39 +5,16 @@ package gov.nist.secauto.metaschema.core.testing; -import org.jmock.Mockery; -import org.jmock.junit5.JUnit5Mockery; -import org.junit.jupiter.api.extension.RegisterExtension; - -import edu.umd.cs.findbugs.annotations.NonNull; - -public class MockedModelTestSupport implements IModuleMockFactory { - @RegisterExtension - @NonNull - Mockery context; +import gov.nist.secauto.metaschema.core.testing.mocking.AbstractMockitoFactory; +public class MockedModelTestSupport + extends AbstractMockitoFactory + implements IModuleMockFactory { /** * Construct a new model mock factory using the default JUnit-based mocking * context. */ public MockedModelTestSupport() { - this(new JUnit5Mockery()); - } - - /** - * Construct a new model mock factory using the provided mocking context. - */ - public MockedModelTestSupport(@NonNull Mockery context) { - this.context = context; - } - - @Override - public Mockery getContext() { - return context; - } - - @Override - public T mock(Class clazz, String name) { - return new MockFactory(getContext()).mock(clazz, name); + // do nothing } } diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/testing/MockFactory.java b/core/src/test/java/gov/nist/secauto/metaschema/core/testing/mocking/AbstractJMockFactory.java similarity index 84% rename from core/src/test/java/gov/nist/secauto/metaschema/core/testing/MockFactory.java rename to core/src/test/java/gov/nist/secauto/metaschema/core/testing/mocking/AbstractJMockFactory.java index a496940a1..ba057b198 100644 --- a/core/src/test/java/gov/nist/secauto/metaschema/core/testing/MockFactory.java +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/testing/mocking/AbstractJMockFactory.java @@ -3,7 +3,7 @@ * SPDX-License-Identifier: CC0-1.0 */ -package gov.nist.secauto.metaschema.core.testing; +package gov.nist.secauto.metaschema.core.testing.mocking; import gov.nist.secauto.metaschema.core.util.ObjectUtils; @@ -14,7 +14,7 @@ import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; -public class MockFactory implements IMockFactory { +public class AbstractJMockFactory implements IMockFactory { @NonNull private final Mockery context; @@ -25,11 +25,11 @@ public class MockFactory implements IMockFactory { * @param ctx * the mocking context */ - public MockFactory(@NonNull Mockery ctx) { + public AbstractJMockFactory(@NonNull Mockery ctx) { this.context = ctx; } - @Override + @NonNull public Mockery getContext() { return context; } diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/testing/mocking/AbstractMockitoFactory.java b/core/src/test/java/gov/nist/secauto/metaschema/core/testing/mocking/AbstractMockitoFactory.java new file mode 100644 index 000000000..7df093730 --- /dev/null +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/testing/mocking/AbstractMockitoFactory.java @@ -0,0 +1,45 @@ +/* + * SPDX-FileCopyrightText: none + * SPDX-License-Identifier: CC0-1.0 + */ + +package gov.nist.secauto.metaschema.core.testing.mocking; + +import static org.mockito.Mockito.withSettings; + +import gov.nist.secauto.metaschema.core.util.ObjectUtils; + +import org.mockito.Answers; +import org.mockito.Mockito; + +import java.util.UUID; + +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; + +public class AbstractMockitoFactory + implements IMockFactory { + + protected AbstractMockitoFactory() { + // allow construction by extending classes + } + + @Override + @NonNull + public T mock(@NonNull Class clazz, @Nullable String name) { + StringBuilder builder = new StringBuilder() + .append(clazz.getSimpleName()); + if (name != null) { + builder + .append('-') + .append(name); + } + builder + .append('-') + .append(UUID.randomUUID().toString()) + .toString(); + return ObjectUtils.notNull(Mockito.mock(clazz, withSettings() + .name(builder.toString()) + .defaultAnswer(Answers.CALLS_REAL_METHODS))); + } +} diff --git a/core/src/test/java/gov/nist/secauto/metaschema/core/testing/IMockFactory.java b/core/src/test/java/gov/nist/secauto/metaschema/core/testing/mocking/IMockFactory.java similarity index 84% rename from core/src/test/java/gov/nist/secauto/metaschema/core/testing/IMockFactory.java rename to core/src/test/java/gov/nist/secauto/metaschema/core/testing/mocking/IMockFactory.java index 42f85a713..9d553ba51 100644 --- a/core/src/test/java/gov/nist/secauto/metaschema/core/testing/IMockFactory.java +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/testing/mocking/IMockFactory.java @@ -3,22 +3,12 @@ * SPDX-License-Identifier: CC0-1.0 */ -package gov.nist.secauto.metaschema.core.testing; - -import org.jmock.Mockery; +package gov.nist.secauto.metaschema.core.testing.mocking; import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.Nullable; public interface IMockFactory { - /** - * Get the mocking context. - * - * @return the mocking context - */ - @NonNull - Mockery getContext(); - /** * Create a mock for the given class. *

diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/codegen/impl/AnnotationGenerator.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/codegen/impl/AnnotationGenerator.java index 7c3efe340..8fcb78df0 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/codegen/impl/AnnotationGenerator.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/codegen/impl/AnnotationGenerator.java @@ -116,7 +116,7 @@ private static void buildConstraint(Class annotationType, AnnotationSpec.Buil annotation.addMember("level", "$T.$L", IConstraint.Level.class, constraint.getLevel()); - String target = constraint.getTarget(); + String target = constraint.getTarget().getPath(); if (!target.equals(getDefaultValue(annotationType, "target"))) { annotation.addMember("target", "$S", target); } @@ -291,7 +291,7 @@ private static void buildKeyFields( for (IKeyField key : keyFields) { AnnotationSpec.Builder keyAnnotation = AnnotationSpec.builder(KeyField.class); - String target = key.getTarget(); + String target = key.getTarget().getPath(); if (!target.equals(getDefaultValue(KeyField.class, "target"))) { keyAnnotation.addMember("target", "$S", target); } @@ -348,7 +348,7 @@ private static void applyExpectConstraints( buildConstraint(Expect.class, constraintAnnotation, constraint); - constraintAnnotation.addMember("test", "$S", constraint.getTest()); + constraintAnnotation.addMember("test", "$S", constraint.getTest().getPath()); if (constraint.getMessage() != null) { constraintAnnotation.addMember("message", "$S", constraint.getMessage()); @@ -433,7 +433,9 @@ private static void checkCardinalities( } else { warn.log(String.format( "Definition '%s' has min-occurs=%d cardinality constraint targeting '%s' that is not a model instance", - definition.getName(), constraint.getMinOccurs(), constraint.getTarget())); + definition.getName(), + constraint.getMinOccurs(), + constraint.getTarget().getPath())); } } } @@ -452,14 +454,18 @@ private static void checkMinOccurs( logBuilder.log(String.format( "Definition '%s' has min-occurs=%d cardinality constraint targeting '%s' that is redundant with a" + " targeted instance named '%s' that requires min-occurs=%d", - definition.getName(), minOccurs, constraint.getTarget(), + definition.getName(), + minOccurs, + constraint.getTarget().getPath(), modelInstance.getName(), modelInstance.getMinOccurs())); } else if (minOccurs < modelInstance.getMinOccurs()) { logBuilder.log(String.format( "Definition '%s' has min-occurs=%d cardinality constraint targeting '%s' that conflicts with a" + " targeted instance named '%s' that requires min-occurs=%d", - definition.getName(), minOccurs, constraint.getTarget(), + definition.getName(), + minOccurs, + constraint.getTarget().getPath(), modelInstance.getName(), modelInstance.getMinOccurs())); } @@ -480,14 +486,18 @@ private static void checkMaxOccurs( logBuilder.log(String.format( "Definition '%s' has max-occurs=%d cardinality constraint targeting '%s' that is redundant with a" + " targeted instance named '%s' that requires max-occurs=%d", - definition.getName(), maxOccurs, constraint.getTarget(), + definition.getName(), + maxOccurs, + constraint.getTarget().getPath(), modelInstance.getName(), modelInstance.getMaxOccurs())); } else if (maxOccurs < modelInstance.getMaxOccurs()) { logBuilder.log(String.format( "Definition '%s' has max-occurs=%d cardinality constraint targeting '%s' that conflicts with a" + " targeted instance named '%s' that requires max-occurs=%d", - definition.getName(), maxOccurs, constraint.getTarget(), + definition.getName(), + maxOccurs, + constraint.getTarget().getPath(), modelInstance.getName(), modelInstance.getMaxOccurs())); } diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/annotations/AllowedValues.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/annotations/AllowedValues.java index e2ee240dc..a6c5fde90 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/annotations/AllowedValues.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/annotations/AllowedValues.java @@ -72,7 +72,7 @@ * @return the target metapath */ @NonNull - String target() default IConstraint.DEFAULT_TARGET_METAPATH; + String target() default "."; /** * An optional set of properties associated with these allowed values. diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/annotations/Expect.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/annotations/Expect.java index da5c93e9c..a37243c0c 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/annotations/Expect.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/annotations/Expect.java @@ -71,7 +71,7 @@ * @return the target metapath */ @NonNull - String target() default IConstraint.DEFAULT_TARGET_METAPATH; + String target() default "."; /** * An optional set of properties associated with these allowed values. diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/impl/ConstraintFactory.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/impl/ConstraintFactory.java index 5bd11da9a..4025bdf79 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/impl/ConstraintFactory.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/impl/ConstraintFactory.java @@ -9,6 +9,7 @@ import gov.nist.secauto.metaschema.core.datatype.IDataTypeAdapter; import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine; import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline; +import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression; import gov.nist.secauto.metaschema.core.model.ISource; import gov.nist.secauto.metaschema.core.model.constraint.AbstractConfigurableMessageConstraintBuilder; import gov.nist.secauto.metaschema.core.model.constraint.AbstractConstraintBuilder; @@ -56,8 +57,12 @@ static MarkupMultiline toRemarks(@NonNull String remarks) { } @NonNull - static String toMetapath(@NonNull String metapath) { - return metapath.isBlank() ? IConstraint.DEFAULT_TARGET_METAPATH : metapath; + static IMetapathExpression toMetapath( + @NonNull String metapath, + @NonNull ISource source) { + return metapath.isBlank() + ? IConstraint.DEFAULT_TARGET_METAPATH + : IMetapathExpression.lazyCompile(metapath, source.getStaticContext()); } @NonNull @@ -85,8 +90,11 @@ static String toMetapath(@NonNull String metapath) { } @NonNull - static > T applyTarget(@NonNull T builder, @NonNull String target) { - builder.target(toMetapath(target)); + static > T applyTarget( + @NonNull T builder, + @NonNull String target, + @NonNull ISource source) { + builder.target(toMetapath(target, source)); return builder; } @@ -166,7 +174,7 @@ static IAllowedValuesConstraint newAllowedValuesConstraint( builder .source(source) .level(constraint.level()); - applyTarget(builder, constraint.target()); + applyTarget(builder, constraint.target(), source); applyProperties(builder, constraint.properties()); applyRemarks(builder, constraint.remarks()); @@ -186,7 +194,7 @@ static IMatchesConstraint newMatchesConstraint(Matches constraint, @NonNull ISou builder .source(source) .level(constraint.level()); - applyTarget(builder, constraint.target()); + applyTarget(builder, constraint.target(), source); applyProperties(builder, constraint.properties()); applyMessage(builder, constraint.message()); applyRemarks(builder, constraint.remarks()); @@ -212,7 +220,7 @@ static IMatchesConstraint newMatchesConstraint(Matches constraint, @NonNull ISou for (KeyField keyField : keyFields) { @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") // ok IKeyField field = IKeyField.of( - toMetapath(keyField.target()), + toMetapath(keyField.target(), source), toPattern(keyField.pattern()), toRemarks(keyField.remarks()), source); @@ -230,7 +238,7 @@ static IUniqueConstraint newUniqueConstraint(@NonNull IsUnique constraint, @NonN builder .source(source) .level(constraint.level()); - applyTarget(builder, constraint.target()); + applyTarget(builder, constraint.target(), source); applyProperties(builder, constraint.properties()); applyMessage(builder, constraint.message()); applyRemarks(builder, constraint.remarks()); @@ -249,7 +257,7 @@ static IIndexConstraint newIndexConstraint(@NonNull Index constraint, @NonNull I builder .source(source) .level(constraint.level()); - applyTarget(builder, constraint.target()); + applyTarget(builder, constraint.target(), source); applyProperties(builder, constraint.properties()); applyMessage(builder, constraint.message()); applyRemarks(builder, constraint.remarks()); @@ -270,7 +278,7 @@ static IIndexHasKeyConstraint newIndexHasKeyConstraint( builder .source(source) .level(constraint.level()); - applyTarget(builder, constraint.target()); + applyTarget(builder, constraint.target(), source); applyProperties(builder, constraint.properties()); applyMessage(builder, constraint.message()); applyRemarks(builder, constraint.remarks()); @@ -289,12 +297,12 @@ static IExpectConstraint newExpectConstraint(@NonNull Expect constraint, @NonNul builder .source(source) .level(constraint.level()); - applyTarget(builder, constraint.target()); + applyTarget(builder, constraint.target(), source); applyProperties(builder, constraint.properties()); applyMessage(builder, constraint.message()); applyRemarks(builder, constraint.remarks()); - builder.test(toMetapath(constraint.test())); + builder.test(toMetapath(constraint.test(), source)); return builder.build(); } @@ -314,7 +322,7 @@ static ICardinalityConstraint newCardinalityConstraint(@NonNull HasCardinality c builder .source(source) .level(constraint.level()); - applyTarget(builder, constraint.target()); + applyTarget(builder, constraint.target(), source); applyProperties(builder, constraint.properties()); applyMessage(builder, constraint.message()); applyRemarks(builder, constraint.remarks()); diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/BindingConstraintLoader.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/BindingConstraintLoader.java index 6555b80ad..6e1e4404b 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/BindingConstraintLoader.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/BindingConstraintLoader.java @@ -5,6 +5,7 @@ package gov.nist.secauto.metaschema.databind.model.metaschema; +import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression; import gov.nist.secauto.metaschema.core.metapath.MetapathException; import gov.nist.secauto.metaschema.core.metapath.StaticContext; import gov.nist.secauto.metaschema.core.model.AbstractLoader; @@ -154,7 +155,7 @@ protected List parseResource(@NonNull URI resource, @NonNull Deq ObjectUtils.notNull(binding.getPrefix()), ObjectUtils.notNull(binding.getUri()))); - ISource source = ISource.externalSource(builder.build()); + ISource source = ISource.externalSource(builder.build(), false); List targetedConstraints = ObjectUtils.notNull(CollectionUtil.listOrEmpty(obj.getContexts()) .stream() @@ -235,7 +236,9 @@ private static AssemblyTargetedConstraints handleScopedAssembly( ConstraintBindingSupport.parse(constraints, obj, source); return new AssemblyTargetedConstraints( source, - ObjectUtils.requireNonNull(obj.getTarget()), + IMetapathExpression.lazyCompile( + ObjectUtils.requireNonNull(obj.getTarget()), + source.getStaticContext()), constraints); } @@ -247,7 +250,9 @@ private static FieldTargetedConstraints handleScopedField( return new FieldTargetedConstraints( source, - ObjectUtils.requireNonNull(obj.getTarget()), + IMetapathExpression.lazyCompile( + ObjectUtils.requireNonNull(obj.getTarget()), + source.getStaticContext()), constraints); } @@ -259,7 +264,9 @@ private static FlagTargetedConstraints handleScopedFlag( return new FlagTargetedConstraints( source, - ObjectUtils.requireNonNull(obj.getTarget()), + IMetapathExpression.lazyCompile( + ObjectUtils.requireNonNull(obj.getTarget()), + source.getStaticContext()), constraints); } @@ -268,18 +275,24 @@ private Context parseContext( @Nullable Context parent, @NonNull ISource source) { - List metapaths; + List metapaths; if (parent == null) { metapaths = ObjectUtils.notNull(CollectionUtil.listOrEmpty(contextObj.getMetapaths()).stream() .map(MetaschemaMetapath::getTarget) + .map(metapath -> IMetapathExpression.lazyCompile( + ObjectUtils.requireNonNull(metapath), + source.getStaticContext())) .collect(Collectors.toList())); } else { - List parentMetapaths = parent.getMetapaths().stream() + List parentMetapaths = parent.getMetapaths().stream() .collect(Collectors.toList()); metapaths = ObjectUtils.notNull(CollectionUtil.listOrEmpty(contextObj.getMetapaths()).stream() .map(MetaschemaMetapath::getTarget) .flatMap(childPath -> parentMetapaths.stream() - .map(parentPath -> parentPath + '/' + childPath)) + .map(parentPath -> parentPath.getPath() + '/' + childPath)) + .map(metapath -> IMetapathExpression.lazyCompile( + ObjectUtils.requireNonNull(metapath), + source.getStaticContext())) .collect(Collectors.toList())); } @@ -301,7 +314,7 @@ private Context parseContext( private static class Context { @NonNull - private final List metapaths; + private final List metapaths; @NonNull private final List childContexts = new LinkedList<>(); @NonNull @@ -309,13 +322,16 @@ private static class Context { public Context( @NonNull ISource source, - @NonNull List metapaths, + @NonNull List metapaths, @NonNull IModelConstrained constraints) { this.metapaths = metapaths; this.targetedConstraints = ObjectUtils.notNull(Lazy.lazy(() -> { Stream paths = getMetapaths().stream() - .map(metapath -> new MetaTargetedContraints(source, ObjectUtils.notNull(metapath), constraints)); + .map(metapath -> new MetaTargetedContraints( + source, + ObjectUtils.notNull(metapath), + constraints)); Stream childPaths = childContexts.stream() .flatMap(child -> child.getTargetedConstraints().stream()); @@ -334,7 +350,7 @@ public void addAll(@NonNull Collection childContexts) { } @NonNull - public List getMetapaths() { + public List getMetapaths() { return metapaths; } } @@ -345,7 +361,7 @@ private static class MetaTargetedContraints protected MetaTargetedContraints( @NonNull ISource source, - @NonNull String target, + @NonNull IMetapathExpression target, @NonNull IModelConstrained constraints) { super(source, target, constraints); } diff --git a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/impl/ConstraintBindingSupport.java b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/impl/ConstraintBindingSupport.java index 4568c591a..f79cee1b5 100644 --- a/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/impl/ConstraintBindingSupport.java +++ b/databind/src/main/java/gov/nist/secauto/metaschema/databind/model/metaschema/impl/ConstraintBindingSupport.java @@ -8,6 +8,7 @@ import gov.nist.secauto.metaschema.core.datatype.IDataTypeAdapter; import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine; import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline; +import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression; import gov.nist.secauto.metaschema.core.metapath.StaticContext; import gov.nist.secauto.metaschema.core.model.ISource; import gov.nist.secauto.metaschema.core.model.constraint.AbstractConfigurableMessageConstraintBuilder; @@ -243,7 +244,7 @@ private static IExpectConstraint newExpect( @NonNull FlagExpect obj, @NonNull ISource source) { IExpectConstraint.Builder builder = IExpectConstraint.builder() - .test(target(ObjectUtils.requireNonNull(obj.getTest()))); + .test(metapath(ObjectUtils.requireNonNull(obj.getTest()), source)); applyConfigurableCommonValues(obj, null, source, builder); String message = obj.getMessage(); @@ -259,7 +260,7 @@ private static IExpectConstraint newExpect( @NonNull TargetedExpectConstraint obj, @NonNull ISource source) { IExpectConstraint.Builder builder = IExpectConstraint.builder() - .test(target(ObjectUtils.requireNonNull(obj.getTest()))); + .test(metapath(ObjectUtils.requireNonNull(obj.getTest()), source)); applyConfigurableCommonValues(obj, obj.getTarget(), source, builder); return builder.build(); @@ -274,7 +275,7 @@ private static IExpectConstraint newExpect( assert value != null; IKeyField keyField = IKeyField.of( - target(ObjectUtils.requireNonNull(value.getTarget())), + metapath(ObjectUtils.requireNonNull(value.getTarget()), source), pattern(value.getPattern()), ModelSupport.remarks(value.getRemarks()), source); @@ -437,17 +438,21 @@ private static IUniqueConstraint newUnique( builder.remarks(ObjectUtils.notNull(remarks.getRemark())); } - builder.target(target(target)); + builder.target(metapath(target, source)); builder.level(level(constraint.getLevel())); builder.source(source); return builder; } @NonNull - private static String target(@Nullable String target) { - return target == null + private static IMetapathExpression metapath( + @Nullable String metapath, + @NonNull ISource source) { + return metapath == null ? IConstraint.DEFAULT_TARGET_METAPATH - : target; + : IMetapathExpression.lazyCompile( + metapath, + source.getStaticContext()); } @NonNull diff --git a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/AbstractGenerationState.java b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/AbstractGenerationState.java index 1dc51b273..ef8796d87 100644 --- a/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/AbstractGenerationState.java +++ b/schemagen/src/main/java/gov/nist/secauto/metaschema/schemagen/AbstractGenerationState.java @@ -93,7 +93,7 @@ protected static AllowedValueCollection getContextIndependentEnumeratedValues( closed = true; } - if (!IMetapathExpression.contextNode().getPath().equals(constraint.getTarget())) { + if (!IMetapathExpression.contextNode().getPath().equals(constraint.getTarget().getPath())) { values = CollectionUtil.emptyList(); break; }