From 1b22585440fd9cc1d50978b21159e49f1e507d13 Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Mon, 22 Jun 2020 17:34:06 +0200 Subject: [PATCH] Axiom: Added test for metadata serialized in Axiom Signed-off-by: Tony Tkacik --- .../evolveum/axiom/api/AxiomValueBuilder.java | 2 +- .../axiom/api/schema/AxiomSchemaContext.java | 6 ++++ .../axiom/api/stream/AxiomItemTarget.java | 8 +++-- .../axiom/lang/spi/AxiomNameResolver.java | 4 +++ .../axiom/src/main/resources/axiom-data.axiom | 7 ++-- .../src/main/resources/axiom-model.axiom | 1 - .../axiom/lang/test/TestAxiomExtension.java | 36 +++++++++++++++++++ .../extension/john-doe-substitution.axiomd | 11 ++++++ 8 files changed, 66 insertions(+), 9 deletions(-) create mode 100644 infra/axiom/src/test/resources/multimodel/extension/john-doe-substitution.axiomd diff --git a/infra/axiom/src/main/java/com/evolveum/axiom/api/AxiomValueBuilder.java b/infra/axiom/src/main/java/com/evolveum/axiom/api/AxiomValueBuilder.java index a4a32521ce2..4ddc039b243 100644 --- a/infra/axiom/src/main/java/com/evolveum/axiom/api/AxiomValueBuilder.java +++ b/infra/axiom/src/main/java/com/evolveum/axiom/api/AxiomValueBuilder.java @@ -69,7 +69,7 @@ public AxiomValue get() { return (AxiomValue) factory.createComplex(type, build(children), build(infra)); } Preconditions.checkState(children.isEmpty(), "%s does not have items. Items found %s", type.name(), children.keySet()); - return factory.createSimple(type, value, Collections.emptyMap()); + return factory.createSimple(type, value, build(infra)); } private static Map> build(Map>> children) { diff --git a/infra/axiom/src/main/java/com/evolveum/axiom/api/schema/AxiomSchemaContext.java b/infra/axiom/src/main/java/com/evolveum/axiom/api/schema/AxiomSchemaContext.java index aacff977e66..875ec3316de 100644 --- a/infra/axiom/src/main/java/com/evolveum/axiom/api/schema/AxiomSchemaContext.java +++ b/infra/axiom/src/main/java/com/evolveum/axiom/api/schema/AxiomSchemaContext.java @@ -9,7 +9,9 @@ import java.util.Collection; import java.util.Optional; +import com.evolveum.axiom.api.AxiomInfraValue; import com.evolveum.axiom.api.AxiomName; +import com.evolveum.axiom.api.AxiomValue; public interface AxiomSchemaContext { @@ -21,4 +23,8 @@ public interface AxiomSchemaContext { Collection types(); + default AxiomTypeDefinition valueInfraType() { + return getType(AxiomValue.AXIOM_VALUE).get(); + } + } diff --git a/infra/axiom/src/main/java/com/evolveum/axiom/api/stream/AxiomItemTarget.java b/infra/axiom/src/main/java/com/evolveum/axiom/api/stream/AxiomItemTarget.java index 4f210098328..734a1ddb436 100644 --- a/infra/axiom/src/main/java/com/evolveum/axiom/api/stream/AxiomItemTarget.java +++ b/infra/axiom/src/main/java/com/evolveum/axiom/api/stream/AxiomItemTarget.java @@ -28,17 +28,19 @@ public class AxiomItemTarget extends AxiomBuilderStreamTarget implements Supplie private final AxiomSchemaContext context; private final AxiomNameResolver resolver; - private AxiomTypeDefinition infraType = AxiomBuiltIn.Type.AXIOM_VALUE; + private final AxiomTypeDefinition infraType; private Item result; public AxiomItemTarget(AxiomSchemaContext context) { this(context, AxiomNameResolver.nullResolver()); + } public AxiomItemTarget(AxiomSchemaContext context, AxiomNameResolver rootResolver) { offer(new Root()); this.context = context; this.resolver = Preconditions.checkNotNull(rootResolver, "rootResolver"); + infraType = context.valueInfraType(); } @Override @@ -122,7 +124,7 @@ public AxiomNameResolver valueResolver() { @Override public AxiomNameResolver infraResolver() { - return AxiomNameResolver.defaultNamespaceFromType(infraType); + return AxiomNameResolver.defaultNamespaceFromType(infraType).or(itemResolver()); } protected Value onlyValue() { @@ -277,7 +279,7 @@ public AxiomName name() { @Override public AxiomNameResolver itemResolver() { - return AxiomNameResolver.defaultNamespaceFromType(builder.type()); + return AxiomNameResolver.defaultNamespaceFromType(builder.type()).or(resolver); } @Override diff --git a/infra/axiom/src/main/java/com/evolveum/axiom/lang/spi/AxiomNameResolver.java b/infra/axiom/src/main/java/com/evolveum/axiom/lang/spi/AxiomNameResolver.java index bd4d3b69451..429c3d67f47 100644 --- a/infra/axiom/src/main/java/com/evolveum/axiom/lang/spi/AxiomNameResolver.java +++ b/infra/axiom/src/main/java/com/evolveum/axiom/lang/spi/AxiomNameResolver.java @@ -44,6 +44,10 @@ static AxiomNameResolver nullResolver() { return NULL_RESOLVER; } + default AxiomNameResolver orPrefix(String prefix, String namespace) { + return or((p, localName) -> prefix.equals(p) ? AxiomName.from(namespace, localName) : null); + } + default AxiomNameResolver or(AxiomNameResolver next) { return (prefix, localName) -> { AxiomName maybe = this.resolveIdentifier(prefix, localName); diff --git a/infra/axiom/src/main/resources/axiom-data.axiom b/infra/axiom/src/main/resources/axiom-data.axiom index 35a9798d887..0d89891948e 100644 --- a/infra/axiom/src/main/resources/axiom-data.axiom +++ b/infra/axiom/src/main/resources/axiom-data.axiom @@ -45,15 +45,14 @@ model axiom-data { item metadata { type ValueMetadata; } + item value { + type DynamicType; + } } type AxiomSimpleValue { supertype AxiomValue; argument value; - - item value { - type DynamicType; - } } type AxiomStructuredValue { diff --git a/infra/axiom/src/main/resources/axiom-model.axiom b/infra/axiom/src/main/resources/axiom-model.axiom index cba40fade4c..c46d57ed414 100644 --- a/infra/axiom/src/main/resources/axiom-model.axiom +++ b/infra/axiom/src/main/resources/axiom-model.axiom @@ -358,7 +358,6 @@ model axiom-model { type MetadataDefinition { supertype AugmentationDefinition; - // TODO: Add limits for specific types item target { const data:ValueMetadata; } diff --git a/infra/axiom/src/test/java/com/evolveum/axiom/lang/test/TestAxiomExtension.java b/infra/axiom/src/test/java/com/evolveum/axiom/lang/test/TestAxiomExtension.java index 9b669e2f0ab..8e4f43168d0 100644 --- a/infra/axiom/src/test/java/com/evolveum/axiom/lang/test/TestAxiomExtension.java +++ b/infra/axiom/src/test/java/com/evolveum/axiom/lang/test/TestAxiomExtension.java @@ -11,6 +11,7 @@ import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; +import java.io.FileNotFoundException; import java.io.IOException; import java.util.Map; import java.util.Optional; @@ -18,13 +19,17 @@ import org.testng.annotations.Test; import com.evolveum.axiom.api.AxiomName; +import com.evolveum.axiom.api.AxiomStructuredValue; import com.evolveum.axiom.api.AxiomValue; import com.evolveum.axiom.api.AxiomItem; import com.evolveum.axiom.api.schema.AxiomItemDefinition; import com.evolveum.axiom.api.schema.AxiomSchemaContext; import com.evolveum.axiom.api.schema.AxiomTypeDefinition; +import com.evolveum.axiom.api.stream.AxiomItemTarget; +import com.evolveum.axiom.lang.antlr.AxiomAntlrStatementSource; import com.evolveum.axiom.lang.api.AxiomBuiltIn.Type; import com.evolveum.axiom.lang.impl.ModelReactorContext; +import com.evolveum.axiom.lang.spi.AxiomNameResolver; import com.evolveum.axiom.lang.spi.AxiomSyntaxException; @@ -43,6 +48,18 @@ public class TestAxiomExtension extends AbstractReactorTest { private static final String METADATA_EXT = DIR + "metadata.axiom"; private static final AxiomName METADATA_MODIFIED = AxiomName.from("https://example.org/metadata", "modified"); + + private static final String DERIVED = "multimodel/derived/"; + private static final String BASE_PERSON = DERIVED + "base-person.axiom"; + private static final String DERIVED_PERSON = DERIVED + "derived-person.axiom"; + private static final String JOHN_DOE_SUBSTITUTION_FILE = DIR + "john-doe-substitution.axiomd"; + + private static final AxiomName DERIVED_PERSON_TYPE = AxiomName.from("https://example.org/derived", "Person"); + + private static final AxiomName NAME = AxiomName.from("https://example.org/base", "name"); + private static final AxiomName FIRST_NAME = DERIVED_PERSON_TYPE.localName("firstName"); + + @Test public void axiomTestExtension() throws IOException, AxiomSyntaxException { ModelReactorContext context = ModelReactorContext.defaultReactor(); @@ -102,11 +119,30 @@ public void axiomTestLanguageExtension() throws IOException, AxiomSyntaxExceptio public void axiomTestMetadata() throws AxiomSyntaxException, IOException { ModelReactorContext context = ModelReactorContext.defaultReactor(); context.loadModelFromSource(source(METADATA_EXT)); + context.loadModelFromSource(source(BASE_PERSON)); + context.loadModelFromSource(source(DERIVED_PERSON)); AxiomSchemaContext schemaContext = context.computeSchemaContext(); AxiomTypeDefinition metadataTypeDef = schemaContext.getType(AxiomValue.METADATA_TYPE).get(); Map defs = metadataTypeDef.itemDefinitions(); assertFalse(defs.isEmpty()); metadataTypeDef.itemDefinition(METADATA_MODIFIED).isPresent(); + + + AxiomAntlrStatementSource stream = dataSource(JOHN_DOE_SUBSTITUTION_FILE); + AxiomItemTarget target = new AxiomItemTarget(schemaContext, + AxiomNameResolver.defaultNamespace(DERIVED_PERSON_TYPE.namespace()) + .orPrefix("mymeta", METADATA_MODIFIED.namespace()) + ); + stream.stream(target); + AxiomItem root = target.get(); + assertEquals(root.name(), DERIVED_PERSON_TYPE.localName("person")); + AxiomStructuredValue person = root.onlyValue().asComplex().get(); + assertEquals(person.item(NAME).get().onlyValue().value(), "John Doe"); + assertEquals(person.item(FIRST_NAME).get().onlyValue().value(), "John"); + assertEquals(person.metadata(METADATA_MODIFIED).get().onlyValue().value(), "structure"); + assertEquals(person.item(FIRST_NAME).get().onlyValue().metadata(METADATA_MODIFIED).get().onlyValue().value(), "substitution"); + + } } diff --git a/infra/axiom/src/test/resources/multimodel/extension/john-doe-substitution.axiomd b/infra/axiom/src/test/resources/multimodel/extension/john-doe-substitution.axiomd new file mode 100644 index 00000000000..0f16538b843 --- /dev/null +++ b/infra/axiom/src/test/resources/multimodel/extension/john-doe-substitution.axiomd @@ -0,0 +1,11 @@ +person "John Doe" { + @metadata { + mymeta:modified "structure"; + } + givenName "John" { + @metadata { + mymeta:modified "substitution"; + } + } + familyName "Doe"; +} \ No newline at end of file