Skip to content

Commit

Permalink
Axiom: Allow to use any of supertypes as item
Browse files Browse the repository at this point in the history
Signed-off-by: Tony Tkacik <tonydamage@gmail.com>
  • Loading branch information
tonydamage committed May 27, 2020
1 parent ebe83b0 commit 281fa78
Show file tree
Hide file tree
Showing 20 changed files with 259 additions and 52 deletions.
11 changes: 11 additions & 0 deletions infra/axiom/src/main/java/com/evolveum/axiom/api/AxiomValue.java
Expand Up @@ -34,4 +34,15 @@ static <V> AxiomValue<V> from(AxiomTypeDefinition typeDefinition, V value) {
return new SimpleValue<V>(typeDefinition, value);
}

default <T> Optional<AxiomValue<T>> onlyValue(Class<T> type, AxiomItemDefinition... components) {
Optional<AxiomValue<?>> current = Optional.of(this);
for(AxiomItemDefinition name : components) {
current = current.get().item(name).map(v -> v.onlyValue());
if(current.isEmpty()) {
return Optional.empty();
}
}
return (Optional) current;
}

}
Expand Up @@ -54,6 +54,7 @@ public Supplier<? extends AxiomItem<?>> get(AxiomIdentifier name, Function<Axiom
public T get() {
Builder<AxiomIdentifier, AxiomItem<?>> builder = ImmutableMap.builder();
for(Entry<AxiomIdentifier, Supplier<? extends AxiomItem<?>>> entry : children.entrySet()) {
AxiomItem<?> item = entry.getValue().get();
builder.put(entry.getKey(), entry.getValue().get());
}
return factory.create(type, value, builder.build());
Expand Down
Expand Up @@ -20,7 +20,7 @@
public interface AxiomTypeDefinition extends AxiomNamedDefinition, AxiomValue<AxiomTypeDefinition> {

public final AxiomIdentifier IDENTIFIER_MEMBER = AxiomIdentifier.axiom("name");
public final AxiomIdentifier IDENTIFIER_SPACE = AxiomIdentifier.axiom("AxiomTypeDefinition");
public final AxiomIdentifier SPACE = AxiomIdentifier.axiom("AxiomTypeDefinition");


@Override
Expand Down
Expand Up @@ -54,6 +54,8 @@ public static class Item implements AxiomItemDefinition {
public static final AxiomItemDefinition ID_SPACE = new Item("space", Type.IDENTIFIER, false);

public static final AxiomItemDefinition TARGET = new Item("target", Type.TYPE_REFERENCE, true);
public static final AxiomItemDefinition REF_TARGET = new Item("target", Type.TYPE_DEFINITION, true);


private final AxiomIdentifier identifier;
private final AxiomTypeDefinition type;
Expand Down Expand Up @@ -128,7 +130,10 @@ public static class Type implements AxiomTypeDefinition {
public static final Type UUID = new Type("uuid");
public static final Type STRING = new Type("string");
public static final Type IDENTIFIER = new Type("AxiomIdentifier");
public static final Type TYPE_REFERENCE = new Type("AxiomTypeReference");
public static final Type TYPE_REFERENCE = new Type("AxiomTypeReference", null, () -> Item.NAME, () -> itemDefs(
Item.NAME,
Item.REF_TARGET
));
public static final Type BASE_DEFINITION =
new Type("AxiomBaseDefinition", null, () -> Item.NAME, () -> itemDefs(
Item.NAME,
Expand Down
Expand Up @@ -8,4 +8,6 @@ public interface AxiomItemContext<T> {

T onlyValue();

void addOperationalValue(AxiomValueReference<T> value);

}
Expand Up @@ -23,7 +23,7 @@ public class AxiomSchemaContextImpl implements AxiomSchemaContext {
public AxiomSchemaContextImpl(Map<AxiomIdentifier,Map<IdentifierSpaceKey, AxiomValue<?>>> globalMap) {
this.globals = globalMap;
this.roots = Maps.transformValues(globalMap.get(AxiomItemDefinition.ROOT_SPACE), AxiomItemDefinition.class::cast);
this.types = Maps.transformValues(globalMap.get(AxiomTypeDefinition.IDENTIFIER_SPACE), AxiomTypeDefinition.class::cast);
this.types = Maps.transformValues(globalMap.get(AxiomTypeDefinition.SPACE), AxiomTypeDefinition.class::cast);
}

@Override
Expand Down Expand Up @@ -53,7 +53,7 @@ private static IdentifierSpaceKey nameKey(AxiomIdentifier type) {
public static AxiomSchemaContextImpl boostrapContext() {
Map<IdentifierSpaceKey, AxiomValue<?>> root = ImmutableMap.of(nameKey(AxiomBuiltIn.Item.MODEL_DEFINITION.name()), AxiomBuiltIn.Item.MODEL_DEFINITION);
Map<AxiomIdentifier, Map<IdentifierSpaceKey, AxiomValue<?>>> global
= ImmutableMap.of(AxiomItemDefinition.ROOT_SPACE, root, AxiomTypeDefinition.IDENTIFIER_SPACE, ImmutableMap.of());
= ImmutableMap.of(AxiomItemDefinition.ROOT_SPACE, root, AxiomTypeDefinition.SPACE, ImmutableMap.of());
return new AxiomSchemaContextImpl(global);
}

Expand Down
Expand Up @@ -27,12 +27,16 @@ default AxiomTypeDefinition typeDefinition() {

Dependency<NamespaceContext> namespace(AxiomIdentifier name, IdentifierSpaceKey namespaceId);

<T> Dependency<AxiomItem<T>> child(AxiomItemDefinition namespace, Class<T> valueType);
<T> Dependency<AxiomItem<T>> child(AxiomItemDefinition item, Class<T> valueType);

<T> Dependency<AxiomValue<T>> onlyItemValue(AxiomItemDefinition item, Class<T> valueType);

Dependency<AxiomValueContext<?>> modify(AxiomIdentifier identifierSpace, IdentifierSpaceKey identifier);

Dependency.Search<AxiomValue<?>> global(AxiomIdentifier identifierSpace, IdentifierSpaceKey identifier);

Dependency.Search<AxiomValueReference<?>> reference(AxiomIdentifier identifierSpace, IdentifierSpaceKey identifier);

Dependency.Search<AxiomValue<?>> namespaceValue(AxiomIdentifier space, IdentifierSpaceKey itemName);

Dependency<V> finalValue();
Expand Down
@@ -0,0 +1,5 @@
package com.evolveum.axiom.lang.impl;

public interface AxiomValueReference<V> {

}
Expand Up @@ -84,15 +84,21 @@ public void apply(Lookup<AxiomIdentifier> context, ActionBuilder<AxiomIdentifier
}

},
EXPAND_TYPE_REFERENCE(items(Item.TYPE_REFERENCE), types(Type.TYPE_REFERENCE)) {
EXPAND_TYPE_REFERENCE(all(), types(Type.TYPE_REFERENCE)) {
@Override
public void apply(Lookup<AxiomIdentifier> context, ActionBuilder<AxiomIdentifier> action) throws AxiomSemanticException {
AxiomIdentifier type = context.originalValue();
Dependency.Search<AxiomValue<?>> typeDef = action.require(context.global(AxiomTypeDefinition.IDENTIFIER_SPACE, AxiomTypeDefinition.identifier(type)));
typeDef.notFound(() -> action.error("type '%s' was not found.", type));
typeDef.unsatisfied(() -> action.error("Referenced type %s is not complete.", type));

Dependency<AxiomValueReference<?>> typeDef = action.require(context.child(Item.NAME, AxiomIdentifier.class)
.unsatisfied(() -> action.error("type name is missing."))
.map(v -> v.onlyValue().get())
.flatMap(name ->
context.reference(AxiomTypeDefinition.SPACE,AxiomTypeDefinition.identifier(name))
.notFound(() -> action.error("type '%s' was not found.", name))
.unsatisfied(() -> action.error("Referenced type %s is not complete.", name))
)
);
action.apply(ctx -> {
ctx.replace(typeDef.get());
ctx.childItem(Item.REF_TARGET).addOperationalValue((AxiomValueReference) typeDef.get());
});
}
},
Expand All @@ -117,24 +123,20 @@ public void apply(Lookup<AxiomIdentifier> context, ActionBuilder<AxiomIdentifier

@Override
public void apply(Lookup<AxiomIdentifier> context, ActionBuilder<AxiomIdentifier> action) throws AxiomSemanticException {
AxiomIdentifier type = context.originalValue();
Dependency<AxiomItem<AxiomIdentifier>> typeName = action.require(context.parentValue().child(Item.NAME, AxiomIdentifier.class))
.unsatisfied(() -> action.error("type does not have name defined"));
Dependency.Search<AxiomValue<?>> typeDef = action.require(context.global(AxiomTypeDefinition.IDENTIFIER_SPACE, AxiomTypeDefinition.identifier(type)));

typeDef.notFound(() -> action.error("type '%s' was not found.", type));
typeDef.unsatisfied(() -> action.error("Referenced type %s is not complete.", type));
Dependency<AxiomTypeDefinition> typeDef =
action.require(
context.onlyItemValue(Item.REF_TARGET, AxiomTypeDefinition.class)
.map(v -> v.get()));
typeDef.unsatisfied(() -> action.error("Supertype is not complete."));
action.apply(superTypeValue -> {
superTypeValue.replace(typeDef.get());
addFromType(typeDef.get(), superTypeValue.parentValue(), typeName.get().onlyValue().get());
addFromType(typeDef.get(), superTypeValue.parentValue(), typeDef.get().name());
});
}


},

IMPORT_DEFAULT_TYPES(all(), types(Type.MODEL)) {

@Override
public void apply(Lookup<AxiomIdentifier> context, ActionBuilder<AxiomIdentifier> action) throws AxiomSemanticException {
Dependency<NamespaceContext> req = action.require(context.namespace(Item.NAMESPACE.name(), namespaceId(AxiomModel.BUILTIN_TYPES)));
Expand Down Expand Up @@ -174,9 +176,10 @@ public void apply(Lookup<AxiomIdentifier> context, ActionBuilder<AxiomIdentifier
@Override
public void apply(Lookup<AxiomIdentifier> context, ActionBuilder<AxiomIdentifier> action) throws AxiomSemanticException {
Dependency<AxiomValueContext<?>> targetRef = action.require(context.child(Item.TARGET, AxiomIdentifier.class)
.map(v -> v.onlyValue().item(Item.NAME).get()))
.flatMap(item ->
context.modify(AxiomTypeDefinition.IDENTIFIER_SPACE, AxiomTypeDefinition.identifier(item.onlyValue().get()))
.unsatisfied(() -> action.error("Target %s not found.",item.onlyValue().get()))
context.modify(AxiomTypeDefinition.SPACE, AxiomTypeDefinition.identifier((AxiomIdentifier) item.onlyValue().get()))
.unsatisfied(() -> action.error("Target %s not found.",item.onlyValue().get())
));
Dependency<AxiomItem<AxiomItemDefinition>> itemDef = action.require(context.child(Item.ITEM_DEFINITION, AxiomItemDefinition.class));
action.apply(ext -> {
Expand Down
Expand Up @@ -58,7 +58,14 @@ protected Optional<AxiomItemDefinition> childDef(AxiomIdentifier id) {

@Override
public boolean isSatisfied() {
return Dependency.allSatisfied(values);
for (Dependency<AxiomValue<V>> value : values) {
if(!(value instanceof ValueContext.ReferenceDependency)) {
if(!value.isSatisfied()) {
return false;
}
}
}
return true;
}

@Override
Expand All @@ -83,6 +90,12 @@ public AxiomValueContext<V> addValue(V value) {
return ret;
}

@Override
public void addOperationalValue(AxiomValueReference<V> value) {
Preconditions.checkState(value instanceof ValueContext.Reference);
values.add(((ValueContext.Reference) value).asDependency());
}

@Override
public V onlyValue() {
Preconditions.checkState(values.size() == 1);
Expand All @@ -99,4 +112,11 @@ public AxiomIdentifierResolver valueResolver() {
return rootImpl().valueResolver();
}

public Dependency<AxiomValue<V>> onlyValue0() {
if(values.size() == 1) {
return values.iterator().next();
}
return null;
}

}
Expand Up @@ -20,6 +20,9 @@ public class ItemValueImpl<V> implements AxiomValue<V> {
private final Map<AxiomIdentifier, AxiomItem<?>> items;


protected <X> X require(Optional<X> value) {
return value.get();
}

public ItemValueImpl(AxiomTypeDefinition type, V value, Map<AxiomIdentifier, AxiomItem<?>> items) {
super();
Expand Down
@@ -0,0 +1,33 @@
package com.evolveum.axiom.lang.impl;

import java.util.Optional;
import java.util.function.Supplier;

import com.evolveum.axiom.api.AxiomValue;
import com.evolveum.axiom.api.schema.AxiomTypeDefinition;

class LazyValue<V> implements AxiomValue<V>{

private final AxiomTypeDefinition type;
private Object delegate;

public LazyValue(AxiomTypeDefinition type, Supplier<AxiomValue<V>> supplier) {
this.type = type;
this.delegate = supplier;
}

@Override
public Optional<AxiomTypeDefinition> type() {
return Optional.of(type);
}

@Override
public V get() {
if(delegate instanceof AxiomValue) {
return ((AxiomValue<V>) delegate).get();
}
delegate = ((Supplier<AxiomValue<V>>)delegate).get();
return get();
}

}
Expand Up @@ -11,7 +11,6 @@
import com.evolveum.axiom.lang.spi.AxiomSemanticException;
import com.evolveum.axiom.reactor.Dependency;
import com.evolveum.axiom.reactor.DependantAction;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
public class ValueActionImpl<V> implements AxiomStatementRule.ActionBuilder<V>, DependantAction<AxiomSemanticException> {

Expand Down Expand Up @@ -91,7 +90,7 @@ public Collection<Dependency<?>> requirements() {

@Override
public void fail(Exception e) throws AxiomSemanticException {
this.error = e;
this.error = new AxiomSemanticException(context.startLocation(), e.getClass().getName() + " " + e.getMessage(), e);
}


Expand Down

0 comments on commit 281fa78

Please sign in to comment.