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 new file mode 100644 index 000000000..09cf2017c --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMAssemblyNodeItem.java @@ -0,0 +1,56 @@ +/* + * SPDX-FileCopyrightText: none + * SPDX-License-Identifier: CC0-1.0 + */ + +package gov.nist.secauto.metaschema.core.mdm; + +import gov.nist.secauto.metaschema.core.mdm.impl.IDMModelNodeItem; +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; + +/** + * An assembly node item implementation that is backed by a simple Metaschema + * module-based data model. + */ +public interface IDMAssemblyNodeItem + extends IAssemblyNodeItem, IDMModelNodeItem { + /** + * 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 + */ + @NonNull + IDMFieldNodeItem newField( + @NonNull IFieldInstance instance, + @NonNull IResourceLocation resourceLocation, + @NonNull IAnyAtomicItem value); + + /** + * Create and add a new assembly to the underlying data model. + * + * @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); +} 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 new file mode 100644 index 000000000..275b5a341 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMDocumentNodeItem.java @@ -0,0 +1,48 @@ +/* + * SPDX-FileCopyrightText: none + * SPDX-License-Identifier: CC0-1.0 + */ + +package gov.nist.secauto.metaschema.core.mdm; + +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; + +import edu.umd.cs.findbugs.annotations.NonNull; + +/** + * A document node item implementation that is backed by a simple Metaschema + * module-based data model. + */ +public interface IDMDocumentNodeItem + extends IDocumentNodeItem { + @Override + IDMRootAssemblyNodeItem getRootAssemblyNodeItem(); + + /** + * Create a new Metaschema document-based data model. + * + * @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); + } +} 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 new file mode 100644 index 000000000..f26e3680f --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMFieldNodeItem.java @@ -0,0 +1,20 @@ +/* + * SPDX-FileCopyrightText: none + * SPDX-License-Identifier: CC0-1.0 + */ + +package gov.nist.secauto.metaschema.core.mdm; + +import gov.nist.secauto.metaschema.core.mdm.impl.IDMModelNodeItem; +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; + +/** + * 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 +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMRootAssemblyNodeItem.java b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMRootAssemblyNodeItem.java new file mode 100644 index 000000000..03cab04ce --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/IDMRootAssemblyNodeItem.java @@ -0,0 +1,17 @@ +/* + * 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.IRootAssemblyNodeItem; + +/** + * A root assembly node item implementation that is backed by a simple + * Metaschema module-based data model. + */ +public interface IDMRootAssemblyNodeItem + extends IDMAssemblyNodeItem, IRootAssemblyNodeItem { + // no additional methods +} 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 new file mode 100644 index 000000000..874a3928a --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/AbstractDMAssemblyNodeItem.java @@ -0,0 +1,104 @@ + +package gov.nist.secauto.metaschema.core.mdm.impl; + +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.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; + +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public abstract class AbstractDMAssemblyNodeItem + extends AbstractNodeItem + 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; + } + + @Override + public String stringValue() { + return ""; + } + + @Override + 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()); + } + + @Override + public List> getModelItemsByName(IEnhancedQName name) { + List> retval = modelItems.get(name); + return retval == null ? CollectionUtil.emptyList() : retval; + } + + @Override + public IDMFieldNodeItem newField(IFieldInstance instance, IResourceLocation resourceLocation, IAnyAtomicItem value) { + List> result = modelItems.computeIfAbsent( + instance.getQName(), + name -> Collections.synchronizedList(new LinkedList>())); + IDMFieldNodeItem field = new FieldImpl(instance, this, resourceLocation, value); + result.add(field); + return field; + } + + @Override + public IDMAssemblyNodeItem newAssembly(IAssemblyInstance instance, IResourceLocation resourceLocation) { + List> result = modelItems.computeIfAbsent( + instance.getQName(), + name -> Collections.synchronizedList(new LinkedList>())); + IDMAssemblyNodeItem assembly = new AssemblyImpl(instance, this, resourceLocation); + result.add(assembly); + return assembly; + } +} 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 new file mode 100644 index 000000000..6d372c501 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/AbstractDMInstanceNodeItem.java @@ -0,0 +1,45 @@ +/* + * 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.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; + +public abstract class AbstractDMInstanceNodeItem< + D extends IDefinition, + I extends INamedInstance, + P extends IModelNodeItem> + extends AbstractInstanceNodeItem + implements INodeItem { + @NonNull + private final IResourceLocation resourceLocation; + + protected AbstractDMInstanceNodeItem( + @NonNull I instance, + @NonNull P parent, + @NonNull IResourceLocation resourceLocation) { + super(instance, parent); + this.resourceLocation = resourceLocation; + } + + @Override + public IResourceLocation getLocation() { + return resourceLocation; + } + + @Override + public StaticContext getStaticContext() { + return getParentNodeItem().getStaticContext(); + } +} 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/AssemblyImpl.java new file mode 100644 index 000000000..7c4e047c7 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/AssemblyImpl.java @@ -0,0 +1,70 @@ +/* + * SPDX-FileCopyrightText: none + * SPDX-License-Identifier: CC0-1.0 + */ + +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 { + @NonNull + private final IAssemblyInstance instance; + @NonNull + private final IDMAssemblyNodeItem parent; + @NonNull + private final IResourceLocation resourceLocation; + + public AssemblyImpl( + @NonNull IAssemblyInstance instance, + @NonNull IDMAssemblyNodeItem parent, + @NonNull IResourceLocation resourceLocation) { + this.instance = instance; + this.parent = parent; + this.resourceLocation = resourceLocation; + } + + @Override + public IResourceLocation getLocation() { + return resourceLocation; + } + + @Override + public int getPosition() { + return getParentNodeItem().getModelItemsByName(getQName()).indexOf(this); + } + + @Override + @NonNull + public IDMAssemblyNodeItem getParentNodeItem() { + return getParentContentNodeItem(); + } + + @Override + @NonNull + public IDMAssemblyNodeItem getParentContentNodeItem() { + return parent; + } + + @Override + public IAssemblyDefinition getDefinition() { + return getInstance().getDefinition(); + } + + @Override + 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/DocumentImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/DocumentImpl.java new file mode 100644 index 000000000..822233e9a --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/DocumentImpl.java @@ -0,0 +1,144 @@ +/* + * SPDX-FileCopyrightText: none + * SPDX-License-Identifier: CC0-1.0 + */ + +package gov.nist.secauto.metaschema.core.mdm.impl; + +import gov.nist.secauto.metaschema.core.mdm.IDMDocumentNodeItem; +import gov.nist.secauto.metaschema.core.mdm.IDMRootAssemblyNodeItem; +import gov.nist.secauto.metaschema.core.metapath.StaticContext; +import gov.nist.secauto.metaschema.core.metapath.item.node.IDocumentNodeItem; +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.IAssemblyDefinition; +import gov.nist.secauto.metaschema.core.model.IResourceLocation; +import gov.nist.secauto.metaschema.core.model.ISource; +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.net.URI; +import java.util.Collection; +import java.util.List; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public class DocumentImpl implements IDMDocumentNodeItem { + @NonNull + private final RootAssembly root; + @NonNull + private final 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; + this.source = ISource.externalSource(resource); + } + + @Override + public URI getDocumentUri() { + return ObjectUtils.notNull(source.getSource()); + } + + @Override + public Collection getFlags() { + // no flags + return CollectionUtil.emptyList(); + } + + @Override + public IFlagNodeItem getFlagByName(IEnhancedQName name) { + // no flags + return null; + } + + @Override + public Collection>> getModelItems() { + return CollectionUtil.singleton(CollectionUtil.singletonList(root)); + } + + @Override + public List> getModelItemsByName(IEnhancedQName name) { + return root.getQName().equals(name) + ? CollectionUtil.singletonList(root) + : CollectionUtil.emptyList(); + } + + @Override + public IResourceLocation getLocation() { + return resourceLocation; + } + + @Override + public String stringValue() { + return ""; + } + + @Override + public StaticContext getStaticContext() { + return source.getStaticContext(); + } + + @Override + public Object getValue() { + return this; + } + + @Override + public String toSignature() { + return ObjectUtils.notNull(new StringBuilder() + .append(getType().toSignature()) + .append('\u2ABB') + .append(getMetapath()) + .append('\u2ABC') + .toString()); + } + + @Override + public IDMRootAssemblyNodeItem getRootAssemblyNodeItem() { + return root; + } + + private class RootAssembly + extends AbstractDMAssemblyNodeItem + implements IDMRootAssemblyNodeItem { + @NonNull + private final IAssemblyDefinition definition; + @NonNull + private final IResourceLocation resourceLocation; + + public RootAssembly( + @NonNull IAssemblyDefinition definition, + @NonNull IResourceLocation location) { + this.definition = definition; + this.resourceLocation = location; + } + + @Override + public IEnhancedQName getQName() { + return definition.getRootQName(); + } + + @Override + public IResourceLocation getLocation() { + return resourceLocation; + } + + @Override + public IDocumentNodeItem getDocumentNodeItem() { + return DocumentImpl.this; + } + + @Override + public IAssemblyDefinition getDefinition() { + return definition; + } + } +} 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/FieldImpl.java new file mode 100644 index 000000000..329efcfc9 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/FieldImpl.java @@ -0,0 +1,109 @@ +/* + * 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.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 + 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); + this.value = value; + } + + @Override + public IAnyAtomicItem toAtomicItem() { + return value; + } + + public void setValue(@NonNull IAnyAtomicItem value) { + this.value = getValueItemType().cast(value); + } + + 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(); + } + + @Override + 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 + return CollectionUtil.emptyList(); + } + + @Override + public List> getModelItemsByName(IEnhancedQName name) { + // no model items + 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/FlagImpl.java b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/FlagImpl.java new file mode 100644 index 000000000..1335777a3 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/FlagImpl.java @@ -0,0 +1,51 @@ +/* + * 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.metapath.item.node.IModelNodeItem; +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 { + @NonNull + private IAnyAtomicItem value; + + public FlagImpl( + @NonNull IFlagInstance instance, + @NonNull IModelNodeItem parent, + @NonNull IResourceLocation resourceLocation, + @NonNull IAnyAtomicItem value) { + super(instance, parent, resourceLocation); + this.value = value; + } + + @Override + public IAnyAtomicItem toAtomicItem() { + return value; + } + + @Override + public Object getValue() { + return this; + } + + @Override + public String stringValue() { + return toAtomicItem().asString(); + } + + @Override + protected String getValueSignature() { + return toAtomicItem().toSignature(); + } +} 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 new file mode 100644 index 000000000..6fa3c2af8 --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/IDMAtomicValuedNodeItem.java @@ -0,0 +1,15 @@ +/* + * 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.node.IAtomicValuedNodeItem; + +public interface IDMAtomicValuedNodeItem extends IAtomicValuedNodeItem { + @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 new file mode 100644 index 000000000..f0df08fdc --- /dev/null +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/mdm/impl/IDMModelNodeItem.java @@ -0,0 +1,25 @@ +/* + * 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.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 { + @NonNull + IFlagNodeItem newFlag( + @NonNull IFlagInstance instance, + @NonNull IResourceLocation resourceLocation, + @NonNull IAnyAtomicItem value); +} diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/StaticContext.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/StaticContext.java index 45ab73d3f..731313041 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/StaticContext.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/StaticContext.java @@ -225,8 +225,7 @@ public String lookupNamespaceForPrefix(@NonNull String prefix) { */ @Nullable public String lookupPrefixForNamespace(@NonNull String namespace) { - String result = lookupPrefixForNamespaceURI(namespace); - return result == null ? XMLConstants.DEFAULT_NS_PREFIX : result; + return lookupPrefixForNamespaceURI(namespace); } /** diff --git a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/DefaultFunctionLibrary.java b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/DefaultFunctionLibrary.java index 50f3b8ec2..92f9ff3a1 100644 --- a/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/DefaultFunctionLibrary.java +++ b/core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/DefaultFunctionLibrary.java @@ -122,6 +122,9 @@ public DefaultFunctionLibrary() { // NOPMD - intentional // https://www.w3.org/TR/xpath-functions-31/#func-month-from-date // https://www.w3.org/TR/xpath-functions-31/#func-month-from-dateTime // https://www.w3.org/TR/xpath-functions-31/#func-months-from-duration + // https://www.w3.org/TR/xpath-functions-31/#func-name + registerFunction(FnName.SIGNATURE_NO_ARG); + registerFunction(FnName.SIGNATURE_ONE_ARG); // https://www.w3.org/TR/xpath-functions-31/#func-node-name // https://www.w3.org/TR/xpath-functions-31/#func-normalize-space registerFunction(FnNormalizeSpace.SIGNATURE_NO_ARG); 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 new file mode 100644 index 000000000..be6597385 --- /dev/null +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnNameTest.java @@ -0,0 +1,114 @@ +/* + * SPDX-FileCopyrightText: none + * SPDX-License-Identifier: CC0-1.0 + */ + +package gov.nist.secauto.metaschema.core.metapath.function.library; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import gov.nist.secauto.metaschema.core.mdm.IDMAssemblyNodeItem; +import gov.nist.secauto.metaschema.core.mdm.IDMDocumentNodeItem; +import gov.nist.secauto.metaschema.core.mdm.IDMFieldNodeItem; +import gov.nist.secauto.metaschema.core.mdm.IDMRootAssemblyNodeItem; +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.item.atomic.IStringItem; +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.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.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.net.URI; +import java.util.stream.Stream; + +import edu.umd.cs.findbugs.annotations.NonNull; +import edu.umd.cs.findbugs.annotations.Nullable; + +class FnNameTest + extends ExpressionTestBase { + @NonNull + private static final IEnhancedQName ROOT_QNAME = IEnhancedQName.of(NS, "root"); + @NonNull + private static final IEnhancedQName ASSEMBLY_QNAME = IEnhancedQName.of(NS, "assembly"); + @NonNull + private static final IEnhancedQName FIELD_QNAME = IEnhancedQName.of(NS, "field"); + @NonNull + private static final IEnhancedQName ASSEMBLY_FLAG_QNAME = IEnhancedQName.of("assembly-flag"); + @NonNull + private static final IEnhancedQName FIELD_FLAG_QNAME = IEnhancedQName.of("field-flag"); + + private IDocumentNodeItem newDocumentNodeItem() { + MockedModelTestSupport mocking = new MockedModelTestSupport(getContext()); + IResourceLocation resourceLocation = mocking.mock(IResourceLocation.class); + + IAssemblyDefinition rootDefinition = mocking.assembly().qname(ROOT_QNAME).rootQName(ROOT_QNAME).toDefinition(); + IAssemblyInstance assemblyInstance = mocking.assembly().qname(ASSEMBLY_QNAME).toInstance(rootDefinition); + IFlagInstance assemblyFlag = mocking.flag().qname(ASSEMBLY_FLAG_QNAME).toInstance(assemblyInstance.getDefinition()); + IFieldInstance fieldInstance = mocking.field().qname(FIELD_QNAME).toInstance(rootDefinition); + IFlagInstance fieldFlag = mocking.flag().qname(FIELD_FLAG_QNAME).toInstance(fieldInstance.getDefinition()); + + IDMDocumentNodeItem document = IDMDocumentNodeItem.newInstance( + URI.create("https://example.com/resource"), + resourceLocation, + rootDefinition, + resourceLocation); + 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")); + + return document; + } + + private static Stream provideValues() { // NOPMD - false positive + return Stream.of( + Arguments.of( + null, + "name()"), + Arguments.of( + null, + "name(.)"), + Arguments.of( + ROOT_QNAME, + "name(/root)"), + Arguments.of( + ASSEMBLY_QNAME, + "name(/root/assembly)"), + Arguments.of( + ASSEMBLY_FLAG_QNAME, + "name(/root/assembly/@assembly-flag)"), + Arguments.of( + FIELD_QNAME, + "name(/root/field)"), + Arguments.of( + FIELD_FLAG_QNAME, + "name(/root/field/@field-flag)")); + } + + @ParameterizedTest + @MethodSource("provideValues") + void test(@Nullable IEnhancedQName expected, @NonNull String metapath) { + DynamicContext dynamicContext = newDynamicContext(); + + IStringItem result = IMetapathExpression.compile(metapath, dynamicContext.getStaticContext()) + .evaluateAs(newDocumentNodeItem(), IMetapathExpression.ResultType.ITEM, dynamicContext); + assertNotNull(result); + assertEquals( + expected == null + ? "" + : expected.toEQName(dynamicContext.getStaticContext()), + result.asString()); + } +} 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 85c758a59..a7d974be8 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 @@ -22,6 +22,12 @@ import edu.umd.cs.findbugs.annotations.NonNull; +/** + * A base class for Metaschema module-based model builders. + * + * @param + * the Java type of this builder + */ public abstract class AbstractModelBuilder> extends MockFactory { @@ -52,7 +58,7 @@ public T reset() { } /** - * Apply the provided namespace to use for names built using this builder. + * Apply the provided namespace for use by this builder. * * @param name * the namespace to use @@ -66,7 +72,7 @@ public T namespace(@NonNull String name) { } /** - * Apply the provided namespace to use for names built using this builder. + * Apply the provided namespace for use by this builder. * * @param name * the namespace to use @@ -75,12 +81,11 @@ public T namespace(@NonNull String name) { @SuppressWarnings("unchecked") @NonNull public T namespace(@NonNull URI name) { - this.namespace = name.toASCIIString(); - return (T) this; + return namespace(name.toASCIIString()); } /** - * Apply the provided names to use for names built using this builder. + * Apply the provided name for use by this builder. * * @param name * the name to use @@ -93,6 +98,21 @@ public T name(@NonNull String name) { return (T) this; } + /** + * Apply the provided qualified name for use by this builder. + * + * @param qname + * the qualified name to use + * @return this builder + */ + @SuppressWarnings("unchecked") + @NonNull + public T qname(@NonNull IEnhancedQName qname) { + this.name = qname.getLocalName(); + this.namespace = qname.getNamespace(); + return (T) this; + } + /** * Validate the data provided to this builder to ensure correct and required * information is provided. 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 f9aaf19e1..3f8da001d 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 @@ -11,10 +11,12 @@ import gov.nist.secauto.metaschema.core.model.INamedModelInstanceAbsolute; 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; @@ -27,6 +29,8 @@ public final class AssemblyBuilder extends AbstractModelBuilder implements IModelInstanceBuilder { + private String rootNamespace = ""; + private String rootName; private List flags; private List modelInstances; @@ -53,6 +57,58 @@ public AssemblyBuilder reset() { return this; } + /** + * Apply the provided root namespace for use by this builder. + * + * @param name + * the namespace to use + * @return this builder + */ + @NonNull + public AssemblyBuilder rootNamespace(@NonNull String name) { + this.rootNamespace = name; + return this; + } + + /** + * Apply the provided root namespace for use by this builder. + * + * @param name + * the namespace to use + * @return this builder + */ + @NonNull + public AssemblyBuilder rootNamespace(@NonNull URI name) { + return rootNamespace(ObjectUtils.notNull(name.toASCIIString())); + } + + /** + * Apply the provided root name for use by this builder. + * + * @param name + * the name to use + * @return this builder + */ + @NonNull + public AssemblyBuilder rootName(@NonNull String name) { + this.rootName = name; + return this; + } + + /** + * Apply the provided root qualified name for use by this builder. + * + * @param qname + * the qualified name to use + * @return this builder + */ + @NonNull + public AssemblyBuilder rootQName(@NonNull IEnhancedQName qname) { + this.rootName = qname.getLocalName(); + this.rootNamespace = qname.getNamespace(); + return this; + } + /** * Use the provided flag instances for built fields. * @@ -132,6 +188,11 @@ public IAssemblyDefinition toDefinition() { 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) -> { 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 new file mode 100644 index 000000000..5f6cc6862 --- /dev/null +++ b/core/src/test/java/gov/nist/secauto/metaschema/core/testing/IModuleMockFactory.java @@ -0,0 +1,42 @@ + +package gov.nist.secauto.metaschema.core.testing; + +import org.jmock.Mockery; + +import edu.umd.cs.findbugs.annotations.NonNull; + +public interface IModuleMockFactory extends IMockFactory { + @Override + @NonNull + Mockery getContext(); + + /** + * Get a new flag builder. + * + * @return the builder + */ + @NonNull + default FlagBuilder flag() { + return FlagBuilder.builder(getContext()); + } + + /** + * Get a new field builder. + * + * @return the builder + */ + @NonNull + default FieldBuilder field() { + return FieldBuilder.builder(getContext()); + } + + /** + * Get a new assembly builder. + * + * @return the builder + */ + @NonNull + default AssemblyBuilder assembly() { + return AssemblyBuilder.builder(getContext()); + } +} 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 72699a074..96d17b74b 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 @@ -11,39 +11,24 @@ import edu.umd.cs.findbugs.annotations.NonNull; -public class MockedModelTestSupport implements IMockFactory { +public class MockedModelTestSupport implements IModuleMockFactory { @RegisterExtension @NonNull - Mockery context = new JUnit5Mockery(); + Mockery context; /** - * Get a new flag builder. - * - * @return the builder + * Construct a new model mock factory using the default JUnit-based mocking + * context. */ - @NonNull - protected FlagBuilder flag() { - return FlagBuilder.builder(context); + public MockedModelTestSupport() { + this(new JUnit5Mockery()); } /** - * Get a new field builder. - * - * @return the builder + * Construct a new model mock factory using the provided mocking context. */ - @NonNull - protected FieldBuilder field() { - return FieldBuilder.builder(context); - } - - /** - * Get a new assembly builder. - * - * @return the builder - */ - @NonNull - protected AssemblyBuilder assembly() { - return AssemblyBuilder.builder(context); + public MockedModelTestSupport(@NonNull Mockery context) { + this.context = context; } @Override