*/
package org.opendaylight.mdsal.binding.runtime.api;
-import static java.util.Objects.requireNonNull;
-
import com.google.common.annotations.Beta;
-import com.google.common.base.MoreObjects;
-import com.google.common.collect.BiMap;
-import com.google.common.collect.ImmutableBiMap;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableMultimap;
-import com.google.common.collect.Multimap;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
-import java.util.Collection;
-import java.util.Map;
import java.util.Optional;
+import java.util.Set;
import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.mdsal.binding.model.api.Type;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.mdsal.binding.model.api.GeneratedType;
+import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
import org.opendaylight.yangtools.concepts.Immutable;
import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.DocumentedNode.WithStatus;
-import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
import org.opendaylight.yangtools.yang.model.api.EffectiveModelContextProvider;
-import org.opendaylight.yangtools.yang.model.api.SchemaNode;
import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
/**
* The result of BindingGenerator run. Contains mapping between Types and SchemaNodes.
*/
@Beta
-public final class BindingRuntimeTypes implements EffectiveModelContextProvider, Immutable {
- private static final VarHandle TYPE_TO_IDENTIFIER;
-
- static {
- try {
- TYPE_TO_IDENTIFIER = MethodHandles.lookup().findVarHandle(BindingRuntimeTypes.class, "typeToIdentifier",
- ImmutableMap.class);
- } catch (NoSuchFieldException | IllegalAccessException e) {
- throw new ExceptionInInitializerError(e);
- }
- }
+public interface BindingRuntimeTypes extends EffectiveModelContextProvider, RuntimeTypeContainer, Immutable {
- private final @NonNull EffectiveModelContext schemaContext;
- private final ImmutableMap<Type, AugmentationSchemaNode> typeToAugmentation;
- private final ImmutableBiMap<Type, WithStatus> typeToSchema;
- private final ImmutableMultimap<Type, Type> choiceToCases;
- private final ImmutableMap<QName, Type> identities;
+ Optional<IdentityRuntimeType> findIdentity(QName qname);
- @SuppressWarnings("unused")
- // Accessed via TYPE_TO_IDENTIFIER
- private volatile ImmutableMap<Type, Absolute> typeToIdentifier = ImmutableMap.of();
+ Optional<RuntimeType> findSchema(JavaTypeName typeName);
- public BindingRuntimeTypes(final EffectiveModelContext schemaContext,
- final Map<Type, AugmentationSchemaNode> typeToAugmentation,
- final BiMap<Type, WithStatus> typeToDefiningSchema, final Multimap<Type, Type> choiceToCases,
- final Map<QName, Type> identities) {
- this.schemaContext = requireNonNull(schemaContext);
- this.typeToAugmentation = ImmutableMap.copyOf(typeToAugmentation);
- this.typeToSchema = ImmutableBiMap.copyOf(typeToDefiningSchema);
- this.choiceToCases = ImmutableMultimap.copyOf(choiceToCases);
- this.identities = ImmutableMap.copyOf(identities);
- }
-
- @Override
- public EffectiveModelContext getEffectiveModelContext() {
- return schemaContext;
- }
+ Optional<InputRuntimeType> findRpcInput(QName rpcName);
- public Optional<AugmentationSchemaNode> findAugmentation(final Type type) {
- return Optional.ofNullable(typeToAugmentation.get(type));
- }
+ Optional<OutputRuntimeType> findRpcOutput(QName rpcName);
- public Optional<Type> findIdentity(final QName qname) {
- return Optional.ofNullable(identities.get(qname));
- }
-
- public Optional<WithStatus> findSchema(final Type type) {
- return Optional.ofNullable(typeToSchema.get(type));
- }
-
- public Optional<Absolute> findSchemaNodeIdentifier(final Type type) {
- final ImmutableMap<Type, Absolute> local = (ImmutableMap<Type, Absolute>) TYPE_TO_IDENTIFIER.getAcquire(this);
- final Absolute existing = local.get(type);
- return existing != null ? Optional.of(existing) : loadSchemaNodeIdentifier(local, type);
- }
-
- public Optional<Type> findType(final WithStatus schema) {
- return Optional.ofNullable(typeToSchema.inverse().get(schema));
- }
-
- public Multimap<Type, Type> getChoiceToCases() {
- return choiceToCases;
- }
-
- public Collection<Type> findCases(final Type choiceType) {
- return choiceToCases.get(choiceType);
- }
-
- @Override
- public String toString() {
- return MoreObjects.toStringHelper(this)
- .add("typeToAugmentation", typeToAugmentation)
- .add("typeToSchema", typeToSchema)
- .add("choiceToCases", choiceToCases)
- .add("identities", identities)
- .toString();
- }
-
- private Optional<Absolute> loadSchemaNodeIdentifier(final ImmutableMap<Type, Absolute> local, final Type type) {
- final WithStatus schema = typeToSchema.get(type);
- if (!(schema instanceof SchemaNode)) {
- return Optional.empty();
- }
-
- // TODO: do not rely on getPath() here
- final Absolute created = Absolute.of(ImmutableList.copyOf(((SchemaNode) schema).getPath().getPathFromRoot()))
- .intern();
-
- ImmutableMap<Type, Absolute> prev = local;
- while (true) {
- // Compute next cache
- final ImmutableMap<Type, Absolute> next =
- ImmutableMap.<Type, Absolute>builderWithExpectedSize(prev.size() + 1)
- .putAll(prev)
- .put(type, created).build();
-
- final Object witness = TYPE_TO_IDENTIFIER.compareAndExchangeRelease(this, prev, next);
- if (witness == prev) {
- // Cache populated successfully, we are all done now
- return Optional.of(created);
- }
-
- // Remember cache for next computation
- prev = (ImmutableMap<Type, Absolute>) witness;
- final Absolute raced = prev.get(type);
- if (raced != null) {
- // We have raced on this item, use it from cache
- return Optional.of(raced);
- }
-
- // We have raced on a different item, loop around and repeat
+ default @Nullable RuntimeType schemaTreeChild(final Absolute path) {
+ final var it = path.getNodeIdentifiers().iterator();
+ var tmp = schemaTreeChild(it.next());
+ while (it.hasNext() && tmp instanceof RuntimeTypeContainer) {
+ tmp = ((RuntimeTypeContainer) tmp).schemaTreeChild(it.next());
}
+ return tmp;
}
+
+ /**
+ * Lookup to all {@link CaseRuntimeType}s related to a {@link ChoiceRuntimeType}. This is important when dealing
+ * with sharing incurred by Binding Spec's reuse of constructs defined in a {@code grouping}.
+ *
+ * <p>
+ * As an example, consider {@link ChoiceRuntimeType} and {@link CaseRuntimeType} relationship to
+ * {@link GeneratedType}s in the following model:
+ * <pre>
+ * <code>
+ * grouping grp {
+ * container foo {
+ * choice bar;
+ * }
+ * }
+ *
+ * container foo {
+ * uses grp;
+ * }
+ *
+ * container bar {
+ * uses grp;
+ * }
+ *
+ * augment /foo/foo/bar {
+ * case baz
+ * }
+ *
+ * augment /bar/foo/bar {
+ * case xyzzy;
+ * }
+ * </code>
+ * </pre>
+ * YANG view of what is valid in {@code /foo/foo/bar} differs from what is valid in {@code /bar/foo/bar}, but this
+ * difference is not reflected in generated Java constructs. More notably, the two augments being in different
+ * modules. Since {@code choice bar}'s is part of a reusable construct, {@code grouping one}, DataObjects' copy
+ * builders can propagate them without translating them to the appropriate manifestation -- and they can do nothing
+ * about that as they lack the complete view of the effective model.
+ *
+ * <p>
+ * This method provides a bridge between a particular instantiation of a {@code choice} to {@link CaseRuntimeType}s
+ * valid in all instantiations.
+ *
+ * @param choiceType A ChoiceRuntimeType
+ * @return The set of {@link CaseRuntimeType}s known to this instance
+ * @throws NullPointerException if {@code ChoiceRuntimeType} is null
+ */
+ @NonNull Set<CaseRuntimeType> allCaseChildren(ChoiceRuntimeType choiceType);
}