final class AugmentationNodeContext<D extends DataObject & Augmentation<?>>
extends DataObjectCodecContext<D, AugmentRuntimeType> {
-
AugmentationNodeContext(final DataContainerCodecPrototype<AugmentRuntimeType> prototype) {
super(prototype);
}
import java.util.List;
import org.opendaylight.mdsal.binding.runtime.api.CaseRuntimeType;
import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.model.api.AddedByUsesAware;
-import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
final class CaseNodeCodecContext<D extends DataObject> extends DataObjectCodecContext<D, CaseRuntimeType> {
CaseNodeCodecContext(final DataContainerCodecPrototype<CaseRuntimeType> prototype) {
- super(prototype);
- }
-
- @Override
- @SuppressWarnings({ "unchecked", "rawtypes" })
- Item<?> createBindingArg(final Class<?> childClass, final EffectiveStatement<?, ?> childSchema) {
- // FIXME: MDSAL-697: see overridden method for further guidance
- return childSchema instanceof AddedByUsesAware aware && aware.isAddedByUses()
- ? Item.of((Class)getBindingClass(), (Class)childClass)
- : super.createBindingArg(childClass, childSchema);
+ super(prototype, CodecItemFactory.of(prototype.getBindingClass()));
}
@Override
--- /dev/null
+/*
+ * Copyright (c) 2023 PANTHEON.tech, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.binding.dom.codec.impl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Verify.verify;
+import static com.google.common.base.Verify.verifyNotNull;
+
+import com.google.common.base.VerifyException;
+import com.google.common.collect.ImmutableMap;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.mdsal.binding.dom.codec.impl.NodeCodecContext.CodecContextFactory;
+import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
+import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
+import org.opendaylight.mdsal.binding.runtime.api.AugmentableRuntimeType;
+import org.opendaylight.mdsal.binding.runtime.api.ChoiceRuntimeType;
+import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType;
+import org.opendaylight.yangtools.yang.binding.Augmentable;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.OpaqueObject;
+import org.opendaylight.yangtools.yang.binding.contract.Naming;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.DistinctNodeContainer;
+
+/**
+ * Analysis of a {@link DataObject} specialization class. The primary point of this class is to separate out creation
+ * indices needed for {@link #proxyConstructor}. Since we want to perform as much indexing as possible in a single pass,
+ * we also end up indexing things that are not strictly required to arrive at that constructor.
+ */
+final class CodecDataObjectAnalysis<R extends CompositeRuntimeType> {
+ private static final MethodType CONSTRUCTOR_TYPE = MethodType.methodType(void.class,
+ DataObjectCodecContext.class, DistinctNodeContainer.class);
+ private static final MethodType DATAOBJECT_TYPE = MethodType.methodType(DataObject.class,
+ DataObjectCodecContext.class, DistinctNodeContainer.class);
+
+ final @NonNull ImmutableMap<Class<?>, DataContainerCodecPrototype<?>> byStreamClass;
+ final @NonNull ImmutableMap<Class<?>, DataContainerCodecPrototype<?>> byBindingArgClass;
+ final @NonNull ImmutableMap<PathArgument, NodeContextSupplier> byYang;
+ final @NonNull ImmutableMap<String, ValueNodeCodecContext> leafNodes;
+ final @NonNull Class<? extends CodecDataObject<?>> generatedClass;
+ final @NonNull List<AugmentRuntimeType> possibleAugmentations;
+ final @NonNull MethodHandle proxyConstructor;
+
+ CodecDataObjectAnalysis(final DataContainerCodecPrototype<R> prototype, final CodecItemFactory itemFactory,
+ final Method keyMethod) {
+ // Preliminaries from prototype
+ @SuppressWarnings("unchecked")
+ final Class<DataObject> bindingClass = Class.class.cast(prototype.getBindingClass());
+ final var runtimeType = prototype.getType();
+ final var factory = prototype.getFactory();
+ final var leafContexts = factory.getLeafNodes(bindingClass, runtimeType.statement());
+
+ // Reflection-based on the passed class
+ final var clsToMethod = getChildrenClassToMethod(bindingClass);
+
+ // Indexing part: be very careful around what gets done when
+ final var byYangBuilder = new HashMap<PathArgument, NodeContextSupplier>();
+
+ // Step 1: add leaf children
+ var leafBuilder = ImmutableMap.<String, ValueNodeCodecContext>builderWithExpectedSize(leafContexts.size());
+ for (var leaf : leafContexts.values()) {
+ leafBuilder.put(leaf.getSchema().getQName().getLocalName(), leaf);
+ byYangBuilder.put(leaf.getDomPathArgument(), leaf);
+ }
+ leafNodes = leafBuilder.build();
+
+ final var byBindingArgClassBuilder = new HashMap<Class<?>, DataContainerCodecPrototype<?>>();
+ final var byStreamClassBuilder = new HashMap<Class<?>, DataContainerCodecPrototype<?>>();
+ final var daoProperties = new HashMap<Class<?>, PropertyInfo>();
+ for (var childDataObj : clsToMethod.entrySet()) {
+ final var method = childDataObj.getValue();
+ verify(!method.isDefault(), "Unexpected default method %s in %s", method, bindingClass);
+
+ final var retClass = childDataObj.getKey();
+ if (OpaqueObject.class.isAssignableFrom(retClass)) {
+ // Filter OpaqueObjects, they are not containers
+ continue;
+ }
+
+ // Record getter method
+ daoProperties.put(retClass, new PropertyInfo.Getter(method));
+
+ final var childProto = getChildPrototype(runtimeType, factory, itemFactory, retClass);
+ byStreamClassBuilder.put(childProto.getBindingClass(), childProto);
+ byYangBuilder.put(childProto.getYangArg(), childProto);
+
+ // FIXME: It really feels like we should be specializing DataContainerCodecPrototype so as to ditch
+ // createInstance() and then we could do an instanceof check instead.
+ if (childProto.getType() instanceof ChoiceRuntimeType) {
+ final var choice = (ChoiceNodeCodecContext<?>) childProto.get();
+ for (var cazeChild : choice.getCaseChildrenClasses()) {
+ byBindingArgClassBuilder.put(cazeChild, childProto);
+ }
+ }
+ }
+
+ // Snapshot before below processing
+ byStreamClass = ImmutableMap.copyOf(byStreamClassBuilder);
+
+ // Slight footprint optimization: we do not want to copy byStreamClass, as that would force its entrySet view
+ // to be instantiated. Furthermore the two maps can easily end up being equal -- hence we can reuse
+ // byStreamClass for the purposes of both.
+ byBindingArgClassBuilder.putAll(byStreamClassBuilder);
+ byBindingArgClass = byStreamClassBuilder.equals(byBindingArgClassBuilder) ? byStreamClass
+ : ImmutableMap.copyOf(byBindingArgClassBuilder);
+
+ // Find all non-default nonnullFoo() methods and update the corresponding property info
+ for (var entry : getChildrenClassToNonnullMethod(bindingClass).entrySet()) {
+ final var method = entry.getValue();
+ if (!method.isDefault()) {
+ daoProperties.compute(entry.getKey(), (key, value) -> new PropertyInfo.GetterAndNonnull(
+ verifyNotNull(value, "No getter for %s", key).getterMethod(), method));
+ }
+ }
+ // At this point all indexing is done: byYangBuilder should not be referenced
+ byYang = ImmutableMap.copyOf(byYangBuilder);
+
+ // Final bits: generate the appropriate class, As a side effect we identify what Augmentations are possible
+ if (Augmentable.class.isAssignableFrom(bindingClass)) {
+ // Verify we have the appropriate backing runtimeType
+ if (!(runtimeType instanceof AugmentableRuntimeType augmentableRuntimeType)) {
+ throw new VerifyException(
+ "Unexpected type %s backing augmenable %s".formatted(runtimeType, bindingClass));
+ }
+
+ possibleAugmentations = augmentableRuntimeType.augments();
+ generatedClass = CodecDataObjectGenerator.generateAugmentable(prototype.getFactory().getLoader(),
+ bindingClass, leafContexts, daoProperties, keyMethod);
+ } else {
+ possibleAugmentations = List.of();
+ generatedClass = CodecDataObjectGenerator.generate(prototype.getFactory().getLoader(), bindingClass,
+ leafContexts, daoProperties, keyMethod);
+ }
+
+ // All done: acquire the constructor: it is supposed to be public
+ final MethodHandle ctor;
+ try {
+ ctor = MethodHandles.publicLookup().findConstructor(generatedClass, CONSTRUCTOR_TYPE);
+ } catch (NoSuchMethodException | IllegalAccessException e) {
+ throw new LinkageError("Failed to find contructor for class " + generatedClass, e);
+ }
+
+ proxyConstructor = ctor.asType(DATAOBJECT_TYPE);
+ }
+
+ private static @NonNull DataContainerCodecPrototype<?> getChildPrototype(final CompositeRuntimeType type,
+ final CodecContextFactory factory, final CodecItemFactory itemFactory,
+ final Class<? extends DataContainer> childClass) {
+ final var child = type.bindingChild(JavaTypeName.create(childClass));
+ if (child == null) {
+ throw DataContainerCodecContext.childNullException(factory.getRuntimeContext(), childClass,
+ "Node %s does not have child named %s", type, childClass);
+ }
+
+ return DataContainerCodecPrototype.from(itemFactory.createItem(childClass, child.statement()),
+ (CompositeRuntimeType) child, factory);
+ }
+
+
+ // FIXME: MDSAL-780: these methods perform analytics using java.lang.reflect to acquire the basic shape of the
+ // class. This is not exactly AOT friendly, as most of the information should be provided by
+ // CompositeRuntimeType.
+ //
+ // As as first cut, CompositeRuntimeType should provide the mapping between YANG children and the
+ // corresponding GETTER_PREFIX/NONNULL_PREFIX method names, If we have that, the use in this
+ // class should be fine.
+ //
+ // The second cut is binding the actual Method invocations, which is fine here, as this class is
+ // all about having a run-time generated class. AOT would be providing an alternative, where the
+ // equivalent class would be generated at compile-time and hence would bind to the methods
+ // directly -- and AOT equivalent of this class would really be a compile-time generated registry
+ // to those classes' entry points.
+
+ /**
+ * Scans supplied class and returns an iterable of all data children classes.
+ *
+ * @param type YANG Modeled Entity derived from DataContainer
+ * @return Iterable of all data children, which have YANG modeled entity
+ */
+ private static Map<Class<? extends DataContainer>, Method> getChildrenClassToMethod(final Class<?> type) {
+ return getChildClassToMethod(type, Naming.GETTER_PREFIX);
+ }
+
+ private static Map<Class<? extends DataContainer>, Method> getChildrenClassToNonnullMethod(final Class<?> type) {
+ return getChildClassToMethod(type, Naming.NONNULL_PREFIX);
+ }
+
+ private static Map<Class<? extends DataContainer>, Method> getChildClassToMethod(final Class<?> type,
+ final String prefix) {
+ checkArgument(type != null, "Target type must not be null");
+ checkArgument(DataContainer.class.isAssignableFrom(type), "Supplied type %s must be derived from DataContainer",
+ type);
+ final var ret = new HashMap<Class<? extends DataContainer>, Method>();
+ for (Method method : type.getMethods()) {
+ DataContainerCodecContext.getYangModeledReturnType(method, prefix)
+ .ifPresent(entity -> ret.put(entity, method));
+ }
+ return ret;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2023 PANTHEON.tech, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.binding.dom.codec.impl;
+
+import static java.util.Objects.requireNonNull;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
+import org.opendaylight.yangtools.yang.model.api.AddedByUsesAware;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+
+sealed class CodecItemFactory {
+ private static final class Case extends CodecItemFactory {
+ private final Class<?> bindingClass;
+
+ Case(final Class<?> bindingClass) {
+ this.bindingClass = requireNonNull(bindingClass);
+ }
+
+ @Override
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ Item<?> createItem(final Class<?> childClass, final EffectiveStatement<?, ?> childSchema) {
+ // FIXME: MDSAL-697: see overridden method for further guidance
+ return childSchema instanceof AddedByUsesAware aware && aware.isAddedByUses()
+ ? Item.of((Class) bindingClass, (Class) childClass) : super.createItem(childClass, childSchema);
+ }
+ }
+
+ private static final @NonNull CodecItemFactory DEFAULT = new CodecItemFactory();
+
+ private CodecItemFactory() {
+ // Hidden on purpose
+ }
+
+ // FIXME: MDSAL-697: move this method into BindingRuntimeContext
+ // This method is only called from loadChildPrototype() and exists only to be overridden by
+ // CaseNodeCodecContext. Since we are providing childClass and our schema to BindingRuntimeContext and
+ // receiving childSchema from it via findChildSchemaDefinition, we should be able to receive the equivalent
+ // of Map.Entry<Item, DataSchemaNode>, along with the override we create here. One more input we may need to
+ // provide is our bindingClass().
+ @SuppressWarnings("unchecked")
+ Item<?> createItem(final Class<?> childClass, final EffectiveStatement<?, ?> childSchema) {
+ return Item.of((Class<? extends DataObject>) childClass);
+ }
+
+ static @NonNull CodecItemFactory of() {
+ return DEFAULT;
+ }
+
+ static @NonNull CodecItemFactory of(final Class<?> bindingClass) {
+ return new Case(bindingClass);
+ }
+}
}
@CheckReturnValue
- private static @NonNull IllegalArgumentException childNullException(final BindingRuntimeContext runtimeContext,
+ static @NonNull IllegalArgumentException childNullException(final BindingRuntimeContext runtimeContext,
final Class<?> childClass, final String message, final Object... args) {
final CompositeRuntimeType schema;
if (Augmentation.class.isAssignableFrom(childClass)) {
package org.opendaylight.mdsal.binding.dom.codec.impl;
import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Verify.verify;
-import static com.google.common.base.Verify.verifyNotNull;
import com.google.common.annotations.Beta;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.ImmutableSet;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
import java.lang.invoke.VarHandle;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Map.Entry;
import java.util.Optional;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.mdsal.binding.dom.codec.api.IncorrectNestingException;
import org.opendaylight.mdsal.binding.model.api.GeneratedType;
-import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
import org.opendaylight.mdsal.binding.model.api.Type;
import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
import org.opendaylight.mdsal.binding.runtime.api.AugmentableRuntimeType;
import org.opendaylight.mdsal.binding.runtime.api.BindingRuntimeContext;
-import org.opendaylight.mdsal.binding.runtime.api.ChoiceRuntimeType;
import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType;
import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
-import org.opendaylight.yangtools.yang.binding.Augmentable;
import org.opendaylight.yangtools.yang.binding.Augmentation;
-import org.opendaylight.yangtools.yang.binding.DataContainer;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
-import org.opendaylight.yangtools.yang.binding.OpaqueObject;
-import org.opendaylight.yangtools.yang.binding.contract.Naming;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.DistinctNodeContainer;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.model.api.DocumentedNode.WithStatus;
-import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class DataObjectCodecContext<D extends DataObject, T extends CompositeRuntimeType>
extends DataContainerCodecContext<D, T> {
private static final Logger LOG = LoggerFactory.getLogger(DataObjectCodecContext.class);
- private static final MethodType CONSTRUCTOR_TYPE = MethodType.methodType(void.class,
- DataObjectCodecContext.class, DistinctNodeContainer.class);
- private static final MethodType DATAOBJECT_TYPE = MethodType.methodType(DataObject.class,
- DataObjectCodecContext.class, DistinctNodeContainer.class);
+
private static final VarHandle MISMATCHED_AUGMENTED;
static {
private volatile ImmutableMap<Class<?>, DataContainerCodecPrototype<?>> mismatchedAugmented = ImmutableMap.of();
DataObjectCodecContext(final DataContainerCodecPrototype<T> prototype) {
- this(prototype, null);
+ this(prototype, CodecItemFactory.of());
}
- DataObjectCodecContext(final DataContainerCodecPrototype<T> prototype, final Method keyMethod) {
- super(prototype);
-
- final Class<D> bindingClass = getBindingClass();
-
- final ImmutableMap<Method, ValueNodeCodecContext> tmpLeaves = factory().getLeafNodes(bindingClass,
- getType().statement());
- final Map<Class<? extends DataContainer>, Method> clsToMethod = getChildrenClassToMethod(bindingClass);
-
- final Map<YangInstanceIdentifier.PathArgument, NodeContextSupplier> byYangBuilder = new HashMap<>();
- final Map<Class<?>, DataContainerCodecPrototype<?>> byStreamClassBuilder = new HashMap<>();
- final Map<Class<?>, DataContainerCodecPrototype<?>> byBindingArgClassBuilder = new HashMap<>();
-
- // Adds leaves to mapping
- final Builder<String, ValueNodeCodecContext> leafChildBuilder =
- ImmutableMap.builderWithExpectedSize(tmpLeaves.size());
- for (final ValueNodeCodecContext leaf : tmpLeaves.values()) {
- leafChildBuilder.put(leaf.getSchema().getQName().getLocalName(), leaf);
- byYangBuilder.put(leaf.getDomPathArgument(), leaf);
- }
- this.leafChild = leafChildBuilder.build();
-
- final Map<Class<?>, PropertyInfo> daoProperties = new HashMap<>();
- for (final Entry<Class<? extends DataContainer>, Method> childDataObj : clsToMethod.entrySet()) {
- final Method method = childDataObj.getValue();
- verify(!method.isDefault(), "Unexpected default method %s in %s", method, bindingClass);
-
- final Class<? extends DataContainer> retClass = childDataObj.getKey();
- if (OpaqueObject.class.isAssignableFrom(retClass)) {
- // Filter OpaqueObjects, they are not containers
- continue;
- }
-
- // Record getter method
- daoProperties.put(retClass, new PropertyInfo.Getter(method));
-
- final DataContainerCodecPrototype<?> childProto = loadChildPrototype(retClass);
- byStreamClassBuilder.put(childProto.getBindingClass(), childProto);
- byYangBuilder.put(childProto.getYangArg(), childProto);
-
- // FIXME: It really feels like we should be specializing DataContainerCodecPrototype so as to ditch
- // createInstance() and then we could do an instanceof check instead.
- if (childProto.getType() instanceof ChoiceRuntimeType) {
- final ChoiceNodeCodecContext<?> choice = (ChoiceNodeCodecContext<?>) childProto.get();
- for (final Class<?> cazeChild : choice.getCaseChildrenClasses()) {
- byBindingArgClassBuilder.put(cazeChild, childProto);
- }
- }
- }
+ DataObjectCodecContext(final DataContainerCodecPrototype<T> prototype, final CodecItemFactory itemFactory) {
+ this(prototype, new CodecDataObjectAnalysis<>(prototype, itemFactory, null));
+ }
- // Find all non-default nonnullFoo() methods and update the corresponding property info
- for (var entry : getChildrenClassToNonnullMethod(bindingClass).entrySet()) {
- final var method = entry.getValue();
- if (!method.isDefault()) {
- daoProperties.compute(entry.getKey(), (key, value) -> new PropertyInfo.GetterAndNonnull(
- verifyNotNull(value, "No getter for %s", key).getterMethod(), method));
- }
- }
+ DataObjectCodecContext(final DataContainerCodecPrototype<T> prototype, final Method keyMethod) {
+ this(prototype, new CodecDataObjectAnalysis<>(prototype, CodecItemFactory.of(), keyMethod));
+ }
- this.byYang = ImmutableMap.copyOf(byYangBuilder);
- this.byStreamClass = ImmutableMap.copyOf(byStreamClassBuilder);
-
- // Slight footprint optimization: we do not want to copy byStreamClass, as that would force its entrySet view
- // to be instantiated. Furthermore the two maps can easily end up being equal -- hence we can reuse
- // byStreamClass for the purposes of both.
- byBindingArgClassBuilder.putAll(byStreamClassBuilder);
- this.byBindingArgClass = byStreamClassBuilder.equals(byBindingArgClassBuilder) ? this.byStreamClass
- : ImmutableMap.copyOf(byBindingArgClassBuilder);
-
- final List<AugmentRuntimeType> possibleAugmentations;
- if (Augmentable.class.isAssignableFrom(bindingClass)) {
- // Verify we have the appropriate backing runtimeType
- final var type = getType();
- verify(type instanceof AugmentableRuntimeType, "Unexpected type %s backing augmenable %s", type,
- bindingClass);
- possibleAugmentations = ((AugmentableRuntimeType) type).augments();
- generatedClass = CodecDataObjectGenerator.generateAugmentable(prototype.getFactory().getLoader(),
- bindingClass, tmpLeaves, daoProperties, keyMethod);
- } else {
- possibleAugmentations = List.of();
- generatedClass = CodecDataObjectGenerator.generate(prototype.getFactory().getLoader(), bindingClass,
- tmpLeaves, daoProperties, keyMethod);
- }
+ private DataObjectCodecContext(final DataContainerCodecPrototype<T> prototype,
+ final CodecDataObjectAnalysis<T> analysis) {
+ super(prototype);
- // Iterate over all possible augmentations, indexing them as needed
- final Map<PathArgument, DataContainerCodecPrototype<?>> augByYang = new HashMap<>();
- final Map<Class<?>, DataContainerCodecPrototype<?>> augByStream = new HashMap<>();
- for (final AugmentRuntimeType augment : possibleAugmentations) {
- final DataContainerCodecPrototype<?> augProto = loadAugmentPrototype(augment);
+ // Inherit analysis stuff
+ leafChild = analysis.leafNodes;
+ proxyConstructor = analysis.proxyConstructor;
+ generatedClass = analysis.generatedClass;
+ byBindingArgClass = analysis.byBindingArgClass;
+ byStreamClass = analysis.byStreamClass;
+ byYang = analysis.byYang;
+
+ // Deal with augmentations, which are not something we analysis provides
+ final var augByYang = new HashMap<PathArgument, DataContainerCodecPrototype<?>>();
+ final var augByStream = new HashMap<Class<?>, DataContainerCodecPrototype<?>>();
+ for (var augment : analysis.possibleAugmentations) {
+ final var augProto = loadAugmentPrototype(augment);
if (augProto != null) {
- final PathArgument augYangArg = augProto.getYangArg();
+ final var augYangArg = augProto.getYangArg();
if (augByYang.putIfAbsent(augYangArg, augProto) == null) {
LOG.trace("Discovered new YANG mapping {} -> {} in {}", augYangArg, augProto, this);
}
- final Class<?> augBindingClass = augProto.getBindingClass();
+ final var augBindingClass = augProto.getBindingClass();
if (augByStream.putIfAbsent(augBindingClass, augProto) == null) {
LOG.trace("Discovered new class mapping {} -> {} in {}", augBindingClass, augProto, this);
}
}
augmentationByYang = ImmutableMap.copyOf(augByYang);
augmentationByStream = ImmutableMap.copyOf(augByStream);
-
- final MethodHandle ctor;
- try {
- ctor = MethodHandles.publicLookup().findConstructor(generatedClass, CONSTRUCTOR_TYPE);
- } catch (NoSuchMethodException | IllegalAccessException e) {
- throw new LinkageError("Failed to find contructor for class " + generatedClass, e);
- }
-
- proxyConstructor = ctor.asType(DATAOBJECT_TYPE);
}
@Override
protected final ValueNodeCodecContext getLeafChild(final String name) {
final ValueNodeCodecContext value = leafChild.get(name);
if (value == null) {
- throw IncorrectNestingException.create("Leaf %s is not valid for %s", name, getBindingClass());
+ throw new IncorrectNestingException("Leaf %s is not valid for %s", name, getBindingClass());
}
return value;
}
- private DataContainerCodecPrototype<?> loadChildPrototype(final Class<? extends DataContainer> childClass) {
- final var type = getType();
- final var child = childNonNull(type.bindingChild(JavaTypeName.create(childClass)), childClass,
- "Node %s does not have child named %s", type, childClass);
-
- return DataContainerCodecPrototype.from(createBindingArg(childClass, child.statement()),
- (CompositeRuntimeType) child, factory());
- }
-
- // FIXME: MDSAL-697: move this method into BindingRuntimeContext
- // This method is only called from loadChildPrototype() and exists only to be overridden by
- // CaseNodeCodecContext. Since we are providing childClass and our schema to BindingRuntimeContext
- // and receiving childSchema from it via findChildSchemaDefinition, we should be able to receive
- // the equivalent of Map.Entry<Item, DataSchemaNode>, along with the override we create here. One
- // more input we may need to provide is our bindingClass().
- @SuppressWarnings("unchecked")
- Item<?> createBindingArg(final Class<?> childClass, final EffectiveStatement<?, ?> childSchema) {
- return Item.of((Class<? extends DataObject>) childClass);
- }
-
private @Nullable DataContainerCodecPrototype<?> augmentationByClass(final @NonNull Class<?> childClass) {
final DataContainerCodecPrototype<?> childProto = augmentationByStream.get(childClass);
return childProto != null ? childProto : mismatchedAugmentationByClass(childClass);
return getDomPathArgument();
}
- /**
- * Scans supplied class and returns an iterable of all data children classes.
- *
- * @param type YANG Modeled Entity derived from DataContainer
- * @return Iterable of all data children, which have YANG modeled entity
- */
- // FIXME: MDSAL-780: replace use of this method
- private static Map<Class<? extends DataContainer>, Method> getChildrenClassToMethod(final Class<?> type) {
- return getChildClassToMethod(type, Naming.GETTER_PREFIX);
- }
-
- // FIXME: MDSAL-780: replace use of this method
- private static Map<Class<? extends DataContainer>, Method> getChildrenClassToNonnullMethod(final Class<?> type) {
- return getChildClassToMethod(type, Naming.NONNULL_PREFIX);
- }
-
- // FIXME: MDSAL-780: replace use of this method
- private static Map<Class<? extends DataContainer>, Method> getChildClassToMethod(final Class<?> type,
- final String prefix) {
- checkArgument(type != null, "Target type must not be null");
- checkArgument(DataContainer.class.isAssignableFrom(type), "Supplied type %s must be derived from DataContainer",
- type);
- final var ret = new HashMap<Class<? extends DataContainer>, Method>();
- for (Method method : type.getMethods()) {
- getYangModeledReturnType(method, prefix).ifPresent(entity -> ret.put(entity, method));
- }
- return ret;
- }
}